Emitir delegado a Func en C #

Tengo código:

public delegate int SomeDelegate(int p); public static int Inc(int p) { return p + 1; } 

Puedo convertir Inc en SomeDelegate o Func :

 SomeDelegate a = Inc; Func b = Inc; 

pero no puedo convertir Inc en SomeDelegate y luego SomeDelegate a Func manera habitual como esta:

 Func c = (Func)a; // Сomstacktion error 

¿Cómo puedo hacerlo?

 SomeDelegate a = Inc; Func b = Inc; 

es la abreviatura de

 SomeDelegate a = new SomeDelegate(Inc); // no cast here Func b = new Func(Inc); 

No puede convertir una instancia de SomeDelegate en Func por el mismo motivo por el que no puede convertir una cadena en un Diccionario ; son tipos diferentes.

Esto funciona:

 Func c = x => a(x); 

que es azúcar sintáctico para

 class MyLambda { SomeDelegate a; public MyLambda(SomeDelegate a) { this.a = a; } public int Invoke(int x) { return this.a(x); } } Func c = new Func(new MyLambda(a).Invoke); 

Hay una manera mucho más simple de hacerlo, que todas las demás respuestas han pasado por alto:

 Func c = a.Invoke; 

Mira esta publicación en el blog para más información.

Prueba esto:

 Func c = (Func)Delegate.CreateDelegate(typeof(Func), b.Target, b.Method); 

El problema es ese:

 SomeDelegate a = Inc; 

No es realmente un elenco. Es la forma abreviada de:

 SomeDelegate a = new SomeDelegate(Inc); 

Por lo tanto, no hay yeso. Una solución simple a su problema puede ser esto (en C # 3.0)

 Func f = i=>a(i); 

Esto funciona (en C # 4.0 al menos, no probado en versiones anteriores):

 SomeDelegate a = Inc; Func c = new Func(a); 

Si miras el IL, comstack exactamente el mismo código que la respuesta de Winston. Aquí está el IL para la segunda línea de lo que acabo de escribir:

 ldloc.0 ldftn instance int32 ConsoleApplication1.Program/SomeDelegate::Invoke(int32) newobj instance void class [mscorlib]System.Func`2::.ctor(object, native int) 

Y eso es precisamente lo que ves si asignas un. a.Invoke en c .

Dicho sea de paso, aunque la solución de Diego es más eficiente, ya que el delegado resultante se refiere directamente al método subyacente en lugar de pasar por el otro delegado, no maneja correctamente los delegates de multidifusión. La solución de Winston sí lo hace, ya que simplemente se remite por completo al otro delegado. Si desea una solución directa que también maneje delegates con objectives múltiples, necesita algo un poco más complejo:

 public static TResult DuplicateDelegateAs(MulticastDelegate source) { Delegate result = null; foreach (Delegate sourceItem in source.GetInvocationList()) { var copy = Delegate.CreateDelegate( typeof(TResult), sourceItem.Target, sourceItem.Method); result = Delegate.Combine(result, copy); } return (TResult) (object) result; } 

Por cierto, esto hace lo correcto para los delegates con un solo objective: terminará produciendo solo un delegado del tipo de destino que se refiere directamente a cualquier método (y, cuando corresponda, objeto) al que se refiera el delegado de entrada.

Es el mismo tipo de problema como este:

 public delegate int SomeDelegate1(int p); public delegate int SomeDelegate2(int p); ... SomeDelegate1 a = new SomeDelegate1(Inc); SomeDelegate2 b = (SomeDelegate2)a; // CS0030 

que es el mismo tipo de problema que:

 public class A { int prop { get; set; } } public class B { int prop { get; set; } } ... A obja = new A(); B objb = (B)obja; // CS0029 

Los objetos no se pueden convertir de un tipo a otro tipo no relacionado, aunque los tipos sean completamente compatibles. A falta de un término mejor: un objeto tiene identidad de tipo que lleva consigo en el tiempo de ejecución. Esa identidad no se puede cambiar después de que se crea el objeto. La manifestación visible de esta identidad es Object.GetType ().

Puedes hackear un elenco usando un truco donde usas el equivalente c # de una unión c ++. La parte difícil es la estructura con dos miembros que tienen un [FieldOffset (0)]:

 [TestFixture] public class Demo { public void print(int i) { Console.WriteLine("Int: "+i); } private delegate void mydelegate(int i); [StructLayout(LayoutKind.Explicit)] struct funky { [FieldOffset(0)] public mydelegate a; [FieldOffset(0)] public System.Action b; } [Test] public void delegatetest() { System.Action f = print; funky myfunky; myfunky.a = null; myfunky.b = f; mydelegate a = myfunky.a; a(5); } } 

Me gustan los ejemplos. Aquí está mi código de ejemplo:

 class Program { class A { public A(D d) { d.Invoke("I'm A!"); } public delegate string D(string s); } class B { public delegate string D(string s); } static void Main(string[] args) { //1. Func to delegates string F(dynamic s) { Console.WriteLine(s); return s; } Func f = F; //new A(f);//Error CS1503 Argument 1: cannot convert from 'System.Func' to 'ConsoleApp3.Program.AD' new A(new AD(f));//I'm A! new A(x=>f(x));//I'm A! Func f2 = s => { Console.WriteLine(s); return s; }; //new A(f2);//Same as A(f) new A(new AD(f2));//I'm A! new A(x => f2(x));//I'm A! //You can even convert between delegate types new A(new AD(new BD(f)));//I'm A! //2. delegate to F AD d = s => { Console.WriteLine(s); return s; }; Func f3 = d.Invoke; f3("I'm f3!");//I'm f3! Func f4 = new Func(d); f4("I'm f4!");//I'm f4! Console.ReadLine(); } } 

El resultado es:

enter image description here