+1 por la rara combinación de ser nuevo en la codificación y hacer una buena pregunta: entiendes lo que quieres hacer y lo explicas bien, simplemente no conoces el término para que no puedas encontrarlo por tu cuenta.
Para completar (en lo que respecta a los diversos comentarios) ...
Como dijo Erik, podría ejecutar múltiples líneas de código:
varButtonClicked=newAction(()=>{MessageBox.Show("hi");MessageBox.Show("something else");// something more useful than another popup ;)});
Como dijo Tim, podría omitir la Actionpalabra clave
ActionButtonClicked=()=>MessageBox.Show("hi");ActionButtonClicked=()=>{// 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é Actiona para especificar un único parámetro de cadena) :Action<string>
Action ButtonClicked = () => MessageBox.Show("hi");es equivalente e IMO más agradable (agregue parens si lo prefiere)
Tim S.
1
También es posible que la acción se resuelva en más de una sola línea de código.
Erik Philips
2
@CSharpie No estoy seguro de que hacer esa suposición sea útil para el OP.
Erik Philips
2
@CSharpie ¿Por qué el OP no pudo usar esto WinForms?
vivat pisces
2
@CSharpie Ya veo lo que estás diciendo. Si en realidad está adjuntando esto a un Button.Clickevento, y no lo almacena en una variable que pasó a nombrar ButtonClicked.
vivat pisces
51
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 functionvoidOnButtonClick(){MessageBox.Show("Hello World!");}// Now we create a delegate called ButtonClickdelegatevoidButtonClick();
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:
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:
delegatevoidButtonClick();voidOnButtonClick(){MessageBox.Show("Hello World!");}voidFoo(){ButtonClickButtonClicked=newButtonClick(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
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:
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í:
También podría jugar, por ejemplo, puede ejecutar una función como esta:
newAction(()=>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:
newAction(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.newAction<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:
newAction<string>(x =>{Console.WriteLine(x);})("I am a string parameter!");
o:
newAction<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:
La Lazyclase 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 =newLazy<DialogResult>(()=>MessageBox.Show("Hello, World!"));var result = foo.Value;
Recuerde que Lazydebe usarse para valores que requieren mucha potencia de procesamiento, y que no debe usarlos para la interacción (porque la semántica de .Valuees que devuelve un valor, similar a una propiedad, no una acción (interactiva)). En su lugar, se debe usar un delegado para tales acciones.
Abel
1
@Abel No, es no para los valores que requieren una gran cantidad de potencia de procesamiento, que es para cualquier valor que le gustaría aplazar la inicialización hasta que se pidió, aunque no siempre la inicialización de ese valor más de una vez. Aquí Valuese usa el valor de ; es el DialogResultrecibido 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.
Servy
Lazypuede 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.
Abel
1
@Abel La sobrecarga de rendimiento Lazyen 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.
Servy
Lo siento, debes haberme entendido mal. Ciertamente, con 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.
Abel
4
La forma en que estoy leyendo tu pregunta, ¿es en el contexto de los controles de la GUI?
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:
Respuestas:
Podrías asignarlo a algo
Action
así:Entonces llámalo:
Para completar (en lo que respecta a los diversos comentarios) ...
Como dijo Erik, podría ejecutar múltiples líneas de código:
Como dijo Tim, podría omitir la
Action
palabra clavePara 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>
fuente
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 nombrarButtonClicked
.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:
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:
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:
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
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:
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:
o incluso más fácil,
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í:También podría jugar, por ejemplo, puede ejecutar una función como esta:
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:
Además, usando genéricos:
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:
o:
EDIT2:
Action<string>
es una representación depublic void delegate Action(string obj);
Action<string,string>
es una representación depublic 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:
o simplemente:
fuente
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:fuente
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 elDialogResult
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 deLazy
. 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 deLazy
. 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 diferir2 + 3 * 4 / i
), donde la sobrecarga de crear el cierre es mayor que el cálculo en sí. Y creo que lo abrazo por completoLazy
, 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:
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:
... tal como estaba preguntando, con una función (o aquí, "Acción", ya que devuelve vacío) asignada como una variable.
fuente
Puede asignar el código C # a una variable, compilarlo en tiempo de ejecución y ejecutar el código:
Escribe tu código:
Cree el proveedor y los parámetros del compilador:
Defina los parámetros del compilador:
Compilar ensamblaje:
Verificar errores:
Obtenga el ensamblaje, el tipo y el método principal:
Ejecutarlo:
Referencia:
http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime
fuente