在C#中将委托转换为Func

时间:2009-12-15 11:22:29

标签: c# .net casting delegates

我有代码:

public delegate int SomeDelegate(int p);

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

我可以将Inc投放到SomeDelegateFunc<int, int>

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

但是我无法将Inc投射到SomeDelegate,然后用这样的惯常方式投射到Func<int, int>

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

我怎么做?

8 个答案:

答案 0 :(得分:59)

有一种更为简单的方法,其他所有答案都错过了:

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

有关详细信息,请参阅this blog post

答案 1 :(得分:45)

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

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

您无法将SomeDelegate的实例强制转换为Func&lt; int,int&gt;出于同样的原因,你不能将字符串转换为Dictionary&lt; int,int&gt; - 他们是不同的类型。

这有效:

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

的语法糖
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);

答案 2 :(得分:24)

试试这个:

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

答案 3 :(得分:8)

问题在于:

SomeDelegate a = Inc;

实际上不是演员。这是简短的形式:

SomeDelegate a = new SomeDelegate(Inc);

因此没有演员。您的问题的简单解决方案可以是这个(在C#3.0中)

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

答案 4 :(得分:7)

这是有效的(至少在C#4.0中 - 未在早期版本中尝试过):

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

如果你看看IL,它会编译成与Winston的答案完全相同的代码。这是我刚才写的第二行的IL:

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

如果您将a.Invoke分配到c,这也正是您所看到的。

顺便提一下,虽然Diego的解决方案更有效,但是生成的委托直接引用底层方法而不是通过另一个委托,它不能正确处理多播委托。温斯顿的解决方案确实如此,因为它完全推迟到另一个代表。如果你想要一个直接的解决方案来处理具有多个目标的委托,你需要一些更复杂的东西:

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;
}

对于具有单个目标的委托来说,这是正确的 - 它最终只会生成目标类型的单个委托,该委托直接引用输入委托所引用的任何方法(以及适用的对象)。

答案 5 :(得分:4)

这是同样的问题:

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

与以下问题类似:

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

对象无法从一种类型转换为不相关的其他类型,即使这些类型完全兼容。缺少更好的术语:对象具有在运行时携带的类型标识。创建对象后无法更改该标识。这种身份的可见表现形式是Object.GetType()。

答案 6 :(得分:4)

你可以使用一个技巧来破解一个演员,你可以使用c#union的c#等价物。棘手的部分是具有两个成员的结构,它们具有[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<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);
    }
}

答案 7 :(得分:0)

我喜欢例子。这是我的示例代码:

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();
    }
}

输出为:

enter image description here