¿Es posible hacer una variable y asignarle una línea de código, como:
ButtonClicked = (MessageBox.Show("Hello, World!"));
... entonces cuando uso la variable, ejecutará la línea de código.
¿Es posible hacer una variable y asignarle una línea de código, como:
ButtonClicked = (MessageBox.Show("Hello, World!"));
... entonces cuando uso la variable, ejecutará la línea de código.
Respuestas:
Podrías asignarlo a algo Action
así:
var ButtonClicked = new Action(() => MessageBox.Show("hi"));
Entonces llámalo:
ButtonClicked();
Para completar (en lo que respecta a los diversos comentarios) ...
Como dijo Erik, podría ejecutar múltiples líneas de código:
var ButtonClicked = new Action(() =>
{
MessageBox.Show("hi");
MessageBox.Show("something else"); // something more useful than another popup ;)
});
Como dijo Tim, podría omitir la Action
palabra clave
Action ButtonClicked = () => MessageBox.Show("hi");
Action ButtonClicked = () =>
{
// multiple lines of code
};
Para abordar el comentario de KRyan, con respecto a los paréntesis vacíos, que representa la lista de parámetros que desea poder enviar a la Acción (en este caso, ninguno) .
Si, por ejemplo, desea especificar el mensaje a mostrar, puede agregar "mensaje" como parámetro (tenga en cuenta que cambié Action
a para especificar un único parámetro de cadena) :Action<string>
Action<string> ButtonClicked = (message) => MessageBox.Show(message);
ButtonClicked("hello world!");
Action ButtonClicked = () => MessageBox.Show("hi");
es equivalente e IMO más agradable (agregue parens si lo prefiere)
WinForms
?
Button.Click
evento, y no lo almacena en una variable que pasó a nombrar ButtonClicked
.
En su caso, desea usar a delegate
.
Veamos cómo funciona un delegado y cómo podemos llegar a una forma más fácil al comprender su concepto:
// Create a normal function
void OnButtonClick()
{
MessageBox.Show("Hello World!");
}
// Now we create a delegate called ButtonClick
delegate void ButtonClick();
Verá, el delegado toma la forma de una función normal pero sin ningún argumento (podría tomar cualquier cantidad de argumentos como cualquier otro método, pero en aras de la simplicidad, no lo hace).
Ahora, usemos lo que tenemos; definiremos el delegado tal como definimos cualquier otra variable:
ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);
Básicamente, creamos una nueva variable llamada ButtonClicked, que tiene un tipo de ButtonClick (que es un delegado) y que, cuando se usa, ejecutará el método en el método OnButtonClick ().
Para usarlo simplemente llamamos:ButtonClicked();
Entonces todo el código sería:
delegate void ButtonClick();
void OnButtonClick()
{
MessageBox.Show("Hello World!");
}
void Foo()
{
ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);
ButtonClicked(); // Execute the function.
}
Desde aquí, podemos pasar a las expresiones lambda y ver cómo podrían ser útiles en su situación:
hay muchos delegados ya definidos por las bibliotecas .NET, con algunos como Acción, que no aceptan ningún parámetro y no devuelven un valor. Se define como public delegate void Action();
Siempre puede usarlo según sus necesidades en lugar de la necesidad de definir un nuevo delegado cada vez. En el contexto anterior, por ejemplo, podría haber escrito
Action ButtonClicked = new Action(OnButtonClick);
ButtonClicked();
que hubiera hecho lo mismo.
Ahora que vio diferentes formas de usar delegados, usemos nuestra primera expresión lambda. Las expresiones lambda son funciones anónimas; entonces, son funciones normales pero sin nombre. Son de esas formas:
x => DoSomethingWithX(x);
(x) => DoSomethingWithX(x);
(x,y) => DoSometingWithXY(x,y);
() => Console.WriteLine("I do not have parameters!");
En nuestro caso, no tenemos ningún parámetro, por lo que utilizaremos la última expresión. Podemos usar esto como la función OnButtonClick, pero tenemos la ventaja de no tener una función con nombre. En cambio, podemos hacer algo como esto:
Action ButtonClicked = new Action( () => MessageBox.Show("Hello World!") );
o incluso más fácil,
Action ButtonClicked = () => MessageBox.Show("Hello World!");
entonces simplemente llame ButtonClicked();
Por supuesto, también puede tener varias líneas de código, pero no quiero confundirlo más. Sin embargo, se vería así:
Action ButtonClicked = () =>
{
MessageBox.Show("Hello World!");
};
ButtonClicked();
También podría jugar, por ejemplo, puede ejecutar una función como esta:
new Action(() => MessageBox.Show("Hello World!"))();
Perdón por la larga publicación, espero que no haya sido demasiado confusa :)
EDITAR: Olvidé mencionar que una forma alternativa que, aunque no se usa con frecuencia, podría hacer que las expresiones lambda sean más fáciles de entender:
new Action(delegate() {
Console.WriteLine("I am parameterless");
})();
Además, usando genéricos:
// Defines a delegate that has one parameter of type string. You could pass as many parameters as you want.
new Action<string>(delegate(string x) {
Console.WriteLine(x);
})("I am a string parameter!");
A su vez, podría usar expresiones lambda, pero no necesita (pero podría en algunos casos) definir el tipo de parámetro, por ejemplo, el código anterior podría simplemente escribirse como:
new Action<string>(x => {
Console.WriteLine(x);
})("I am a string parameter!");
o:
new Action<string>(x => Console.WriteLine(x))("I am a string parameter!");
EDIT2:
Action<string>
es una representación de public void delegate Action(string obj);
Action<string,string>
es una representación de public void delegate Action(string obj, string obj2);
En general, Action<T>
es una representación depublic void delegate Action<T>(T obj);
EDIT3: Sé que la publicación ha estado aquí por un tiempo, pero creo que es genial no mencionarlo: puedes hacer esto, que está relacionado principalmente con tu pregunta:
dynamic aFunction = (Func<string, DialogResult>)MessageBox.Show;
aFunction("Hello, world!");
o simplemente:
Func<string, DialogResult> aFunction = MessageBox.Show;
aFunction("Hello, world!");
La Lazy
clase está diseñada específicamente para representar un valor que no se calculará hasta que lo solicite. Lo construye proporcionando un método que define cómo debe construirse, pero se encargará de ejecutar ese método no más de una vez (incluso frente a múltiples subprocesos que solicitan el valor) y simplemente devolver el valor ya construido para cualquier solicitud adicional:
var foo = new Lazy<DialogResult>(()=>MessageBox.Show("Hello, World!"));
var result = foo.Value;
Lazy
debe usarse para valores que requieren mucha potencia de procesamiento, y que no debe usarlos para la interacción (porque la semántica de .Value
es que devuelve un valor, similar a una propiedad, no una acción (interactiva)). En su lugar, se debe usar un delegado para tales acciones.
Value
se usa el valor de ; es el DialogResult
recibido al mostrar el cuadro de mensaje. La principal diferencia entre esta solución y el uso de un delegado es si el valor se debe volver a calcular cada vez que se solicita o no. Mi interpretación de los requisitos fue que esto inicializa conceptualmente un valor, no una operación que se repita.
Lazy
puede ser usado incorrectamente fácilmente. Tiene sobrecarga de sí mismo, usarlo "solo" para diferir una tarea pequeña invocará más sobrecarga de la que gana. Mostrar cuadros de mensaje de una propiedad es (imo) una mala práctica en general, independientemente de Lazy
. Por cierto, de MSDN, cito: "Use la inicialización diferida para diferir la creación de un objeto grande o que requiera muchos recursos" . Puede estar en desacuerdo con eso, pero para eso fue diseñado originalmente.
Lazy
en un contexto como este es ciertamente insignificante; palidecerá en comparación con el tiempo dedicado a esperar que un humano haga clic en un cuadro de mensaje. Principalmente se reduce a los requisitos reales de la aplicación subyacente; La vaguedad de la pregunta hace imposible una respuesta objetivamente correcta. Esta es una interpretación de la pregunta. En cuanto a que hacer mucho trabajo en un captador de propiedades es malo; aparentemente te opones fundamentalmente a todo el diseño de Lazy
. De nada a esa opinión.
MessageBox
la sobrecarga es insignificante (simplemente no usaría la interfaz de usuario dentro de una propiedad). Me refería a pequeñas tareas en general (como diferir 2 + 3 * 4 / i
), donde la sobrecarga de crear el cierre es mayor que el cálculo en sí. Y creo que lo abrazo por completo Lazy
, de hecho lo usamos mucho en F # (poco menos en C #) y hemos aprendido de la manera difícil que hay que tener cuidado con eso, especialmente. en respeto con el rendimiento.
La forma en que estoy leyendo tu pregunta, ¿es en el contexto de los controles de la GUI?
Si esto está en WPF, eche un vistazo a la forma "correcta" de manejar los comandos de los controles: http://msdn.microsoft.com/en-us/library/ms752308(v=vs.110).aspx
... pero eso puede ser un dolor y una exageración. Para un caso general más simple, es posible que esté buscando un controlador de eventos, como:
myButton.Click += (o, e) => MessageBox.Show("Hello, World!");
Ese controlador de eventos se puede manejar de varias maneras. El ejemplo anterior usa una función anónima, pero también podría hacer:
Action<object, RoutedEventArgs> sayHello = (o, e) => MessageBox.Show("Hello, World");
myButton.Click += new RoutedEventHandler(sayHello);
... tal como estaba preguntando, con una función (o aquí, "Acción", ya que devuelve vacío) asignada como una variable.
Puede asignar el código C # a una variable, compilarlo en tiempo de ejecución y ejecutar el código:
Escribe tu código:
// Assign C# code to the code variable.
string code = @"
using System;
namespace First
{
public class Program
{
public static void Main()
{
" +
"Console.WriteLine(\"Hello, world!\");"
+ @"
}
}
}
";
Cree el proveedor y los parámetros del compilador:
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
Defina los parámetros del compilador:
// Reference to System.Drawing library
parameters.ReferencedAssemblies.Add("System.Drawing.dll");
// True - memory generation, false - external file generation
parameters.GenerateInMemory = true;
// True - exe file generation, false - dll file generation
parameters.GenerateExecutable = true;
Compilar ensamblaje:
CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
Verificar errores:
if (results.Errors.HasErrors)
{
StringBuilder sb = new StringBuilder();
foreach (CompilerError error in results.Errors)
{
sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
}
throw new InvalidOperationException(sb.ToString());
}
Obtenga el ensamblaje, el tipo y el método principal:
Assembly assembly = results.CompiledAssembly;
Type program = assembly.GetType("First.Program");
MethodInfo main = program.GetMethod("Main");
Ejecutarlo:
main.Invoke(null, null);
Referencia:
http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime