在C#中将代理投射到Func

我有代码:

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

我可以把IncSomeDelegate或者Func<int, int>

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

但是我不能把IncSomeDelegate ,然后用像这样的常用方法SomeDelegateFunc<int, int>

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

我怎么能做到这一点?

 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 <int,int>,因为你不能把一个string转换成一个Dictionary <int,int> – 它们是不同的types。

这工作:

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

有一个更简单的方法来做到这一点,所有其他的答案已经错过了:

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

看到这个博客文章了解更多信息。

尝试这个:

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

问题是:

 SomeDelegate a = Inc; 

实际上不是一个演员。 这是简短的forms:

 SomeDelegate a = new SomeDelegate(Inc); 

所以没有演员。 一个简单的解决scheme可以是这个(在C#3.0)

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

这工作(至less在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

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

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

这样做对于具有单个目标的委托人来说是正确的 – 它将最终生成目标types的单个委托,该委派直接引用input委托所涉及的任何方法(以及适用的对象)。

这是同样的问题:

 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 

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

你可以通过使用c ++等效的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); } }