it-swarm.com.de

Besetzungsdelegierter an Func in C #

Ich habe Code:

public delegate int SomeDelegate(int p);

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

Ich kann Inc in SomeDelegate oder Func<int, int> umwandeln:

SomeDelegate a = Inc;
Func<int, int> b = Inc;

aber ich kann Inc nicht in SomeDelegate und anschließend in Func<int, int> mit der üblichen Art und Weise wie folgt umwandeln:

Func<int, int> c = (Func<int, int>)a; // Сompilation error

Wie kann ich es tun?

39
AndreyAkinshin
SomeDelegate a = Inc;
Func<int, int> b = Inc;

ist die Abkürzung für

SomeDelegate a = new SomeDelegate(Inc); // no cast here
Func<int, int> b = new Func<int, int>(Inc);

Sie können eine Instanz von SomeDelegate nicht in eine Func <int, int> umwandeln. Aus demselben Grund können Sie keine Zeichenfolge in ein Dictionary <int, int> umwandeln. Es handelt sich um unterschiedliche Typen.

Das funktioniert:

Func<int, int> c = x => a(x);

welches ist syntaktischer Zucker für

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

Func<int, int> c = new Func<int, int>(new MyLambda(a).Invoke);
45
dtb

Es gibt einen viel einfacheren Weg, den alle anderen Antworten übersehen haben:

Func<int, int> c = a.Invoke; 

Siehe diesen Blogbeitrag für weitere Informationen.

57
Winston Smith

Versuche dies:

Func<int, int> c = (Func<int, int>)Delegate.CreateDelegate(typeof(Func<int, int>), 
                                                           b.Target,
                                                           b.Method);
24
Diego Mijelshon

Das Problem ist, dass:

SomeDelegate a = Inc;

Ist eigentlich keine Besetzung. Es ist die Kurzform von:

SomeDelegate a = new SomeDelegate(Inc);

Deshalb gibt es keine Besetzung. Eine einfache Lösung für Ihr Problem kann dies sein (in C # 3.0)

Func<int,int> f = i=>a(i);
8
Gamlor

Dies funktioniert (zumindest in C # 4.0 - in früheren Versionen nicht versucht):

SomeDelegate a = Inc;
Func<int, int> c = new Func<int, int>(a);

Wenn Sie sich die AW anschauen, ergibt dies genau den gleichen Code wie die Antwort von Winston. Hier ist die IL für die zweite Zeile von dem, was ich gerade geschrieben habe:

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

Und genau das sehen Sie auch, wenn Sie ca.Invoke zuweisen.

Obwohl die Lösung von Diego zwar effizienter ist, bezieht sich der resultierende Delegat zwar direkt auf die zugrunde liegende Methode, anstatt den anderen Delegaten zu durchlaufen, er behandelt jedoch Multicast-Delegaten nicht richtig. Die Lösung von Winston tut dies, weil sie sich ganz dem anderen Delegierten verschiebt. Wenn Sie eine direkte Lösung suchen, die auch Delegierte mit mehreren Zielen behandelt, benötigen Sie etwas komplexeres:

public static TResult DuplicateDelegateAs<TResult>(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;
}

Dies ist übrigens für Delegierte mit einem einzigen Ziel das Richtige - es wird letztendlich nur ein einzelner Delegat des Zieltyps erzeugt, der sich direkt auf die Methode (und ggf. Objekt) bezieht, auf die der Eingabedelegierte verweist.

7
Ian Griffiths

Es ist das gleiche Problem wie dieses:

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

das ist das gleiche Problem wie:

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

Objekte können nicht von einem Typ in einen nicht verwandten anderen Typ umgewandelt werden, auch wenn die Typen sonst vollständig kompatibel sind. Mangels eines besseren Begriffs: Ein Objekt hat eine Typidentität, die es zur Laufzeit mit sich führt. Diese Identität kann nicht geändert werden, nachdem das Objekt erstellt wurde. Die sichtbare Manifestation dieser Identität ist Object.GetType ().

4
Hans Passant

Sie können einen Cast hacken, indem Sie einen Trick verwenden, bei dem Sie das c # -Äquivalent einer c ++ - Vereinigung verwenden. Der schwierige Teil ist die Struktur mit zwei Mitgliedern, die ein [FieldOffset (0)] haben:

[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<int> b;
    }

    [Test]
    public void delegatetest()
    {
        System.Action<int> f = print;
        funky myfunky;
        myfunky.a = null;
        myfunky.b = f;

        mydelegate a = myfunky.a;

        a(5);
    }
}
4
Lucas Meijer

Ich mag Beispiele. Hier ist mein Beispielcode:

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<string, string> f = F;
        //new A(f);//Error CS1503  Argument 1: cannot convert from 'System.Func<string, string>' to 'ConsoleApp3.Program.A.D'  
        new A(new A.D(f));//I'm A!
        new A(x=>f(x));//I'm A!

        Func<string, string> f2 = s => { Console.WriteLine(s); return s; };
        //new A(f2);//Same as A(f)
        new A(new A.D(f2));//I'm A!
        new A(x => f2(x));//I'm A!

        //You can even convert between delegate types
        new A(new A.D(new B.D(f)));//I'm A!



        //2. delegate to F

        A.D d = s => { Console.WriteLine(s); return s; };

        Func<string, string> f3 = d.Invoke;
        f3("I'm f3!");//I'm f3!
        Func<string, string> f4 = new Func<string, string>(d);
        f4("I'm f4!");//I'm f4!


        Console.ReadLine();
    }
}

Die Ausgabe ist:

 enter image description here

0
tymtam