c# - que - Acción para delegar: ¿nueva acción o acción de lanzamiento?
proceso para delegar en las organizaciones (3)
En mi opinión, no hay diferencia.
new Action(() => DoNothing(param));
Esto solo crea una nueva Acción y pasa a lo largo de una expresión Lambda, que el compilador tratará y se asegurará de que todo esté bien conectado.
(Action)(() => DoNothing(param));
Esto funciona porque un método lambda como este no devuelve ningún valor y no toma ningún parámetro, como tal, el compilador puede verificar que es "asignable" a una Acción basándose en que pasa por el sistema delegado.
Son más o menos uno y lo mismo, dependiendo de cualquier tipo de optimizaciones de compilador, es difícil decir cuál es más eficiente, quizás debería probar el rendimiento y verlo usted mismo.
Es una pregunta interesante y una exploración del sistema de delegación y cómo Linq y Expressions encajan.
new Func<string>(() => "Boo!");
es más o menos equivalente a:
(Func<String>)() => "Boo!";
Por lo que sé, ambos terminan descendiendo por el sistema de delegados, piensan en Invoke()
, etc., sería interesante si probaran el rendimiento y compartieran sus resultados.
Encontré dos formas diferentes de inicializar un delegado con una acción:
Crea una nueva acción o conversión a Acción.
Delegate foo = new Action(() => DoNothing(param));
Delegate bar = (Action)(() => DoNothing(param));
¿Hay alguna diferencia entre estas 2 sintaxis?
¿Cuál es mejor y por qué?
Editar:
El delegado se usa en este ejemplo porque la sintaxis es útil para llamar a métodos como BeginInvoke o Invoke con una expresión lambda, y es importante convertir la expresión lambda en una acción.
static main
{
Invoke((Action)(() => DoNothing())); // OK
Invoke(new Action(() => DoNothing())); // OK
Invoke(() => DoNothing()); // Doesn''t compil
}
private static void Invoke(Delegate del) { }
Pero es interesante ver que el compilador autorizó esto:
Action action = () => DoNothing();
Invoke(action);
No hay diferencia entre estas dos instrucciones. En ambas instrucciones, se crea una nueva instancia de Acción.
El código IL a continuación parece confirmar esto.
Programa de consola:
class Program
{
static void Main(string[] args)
{
Delegate barInit = (Action)(() => DoNothing());
Delegate fooInit = new Action(() => DoNothing());
}
private static void DoNothing() { }
}
Código IL:
// First instruction
IL_0000: ldsfld class [mscorlib]System.Action CodeMachineTest.Program::''CS$<>9__CachedAnonymousMethodDelegate2''
IL_0005: brtrue.s IL_0018
IL_0007: ldnull
IL_0008: ldftn void CodeMachineTest.Program::''<Main>b__0''()
// Create a new Action instance for the instruction (Action)(() => DoNothing())
IL_000e: newobj instance void [mscorlib]System.Action::.ctor(object, native int)
IL_0013: stsfld class [mscorlib]System.Action CodeMachineTest.Program::''CS$<>9__CachedAnonymousMethodDelegate2''
IL_0018: ldsfld class [mscorlib]System.Action CodeMachineTest.Program::''CS$<>9__CachedAnonymousMethodDelegate2''
IL_001d: pop
// Second instruction
IL_001e: ldsfld class [mscorlib]System.Action CodeMachineTest.Program::''CS$<>9__CachedAnonymousMethodDelegate3''
IL_0023: brtrue.s IL_0036
IL_0025: ldnull
IL_0026: ldftn void CodeMachineTest.Program::''<Main>b__1''()
IL_002c: newobj instance void [mscorlib]System.Action::.ctor(object, native int)
IL_0031: stsfld class [mscorlib]System.Action CodeMachineTest.Program::''CS$<>9__CachedAnonymousMethodDelegate3''
IL_0036: ldsfld class [mscorlib]System.Action CodeMachineTest.Program::''CS$<>9__CachedAnonymousMethodDelegate3''
IL_003b: pop
IL_003c: ret
No hay diferencia, solo son dos sintaxis para lo mismo. Personalmente, utilizo el último, porque es más corto.
Pero, ¿por qué necesitas una variable de tipo Delegate
? En la mayoría de los casos, desea que la variable tenga el mismo tipo que la instancia, y luego puede usar
var bar = (Action)(() => DoNothing(param));
o
Action bar = () => DoNothing(param);
en lugar de
Delegate bar = (Action)(() => DoNothing(param)); // (from your question)