在 C# 中将委托转换为 Func
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1906787/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Cast delegate to Func in C#
提问by AndreyAkinshin
I have code:
我有代码:
public delegate int SomeDelegate(int p);
public static int Inc(int p) {
return p + 1;
}
I can cast Inc
to SomeDelegate
or Func<int, int>
:
我可以投射Inc
到SomeDelegate
或Func<int, int>
:
SomeDelegate a = Inc;
Func<int, int> b = Inc;
but I can't cast Inc
to SomeDelegate
and after that cast to Func<int, int>
with usual way like this:
但我不能像这样通常的方式投射Inc
到SomeDelegate
和之后投射到Func<int, int>
:
Func<int, int> c = (Func<int, int>)a; // Сompilation error
How I can do it?
我该怎么做?
采纳答案by dtb
SomeDelegate a = Inc;
Func<int, int> b = Inc;
is short for
是简称
SomeDelegate a = new SomeDelegate(Inc); // no cast here
Func<int, int> b = new Func<int, int>(Inc);
You can't cast an instance of SomeDelegate to a Func<int, int> for the same reason you can't cast a string to a Dictionary<int, int> -- they're different types.
您不能将 SomeDelegate 的实例转换为 Func<int, int> ,原因与不能将字符串转换为 Dictionary<int, int> 的原因相同——它们是不同的类型。
This works:
这有效:
Func<int, int> c = x => a(x);
which is syntactic sugar for
这是语法糖
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);
回答by Diego Mijelshon
Try this:
尝试这个:
Func<int, int> c = (Func<int, int>)Delegate.CreateDelegate(typeof(Func<int, int>),
b.Target,
b.Method);
回答by Gamlor
The problem is that:
问题在于:
SomeDelegate a = Inc;
Isn't actually a cast. It's the short-form of:
实际上不是演员表。它的缩写形式为:
SomeDelegate a = new SomeDelegate(Inc);
Therefore there's no cast. A simple solution to your problem can be this (in C# 3.0)
因此没有演员阵容。您的问题的简单解决方案可以是这个(在 C# 3.0 中)
Func<int,int> f = i=>a(i);
回答by Hans Passant
It is the same kind of problem as this:
这是同一种问题:
public delegate int SomeDelegate1(int p);
public delegate int SomeDelegate2(int p);
...
SomeDelegate1 a = new SomeDelegate1(Inc);
SomeDelegate2 b = (SomeDelegate2)a; // CS0030
which is the same kind of problem as:
这与以下问题相同:
public class A { int prop { get; set; } }
public class B { int prop { get; set; } }
...
A obja = new A();
B objb = (B)obja; // CS0029
Objects cannot be casted from one type to an unrelated other type, even though the types are otherwise completely compatible. For lack of a better term: an object has type identity that it carries along at runtime. That identity cannot be changed after the object is created. The visible manifestation of this identity is Object.GetType().
对象不能从一种类型转换为不相关的其他类型,即使这些类型在其他方面完全兼容。由于缺乏更好的术语:对象具有它在运行时携带的类型标识。创建对象后,该标识无法更改。此标识的可见表现形式是 Object.GetType()。
回答by Winston Smith
There's a much simpler way to do it, which all the other answers have missed:
有一种更简单的方法来做到这一点,所有其他答案都错过了:
Func<int, int> c = a.Invoke;
See this blog postfor more info.
有关更多信息,请参阅此博客文章。
回答by Ian Griffiths
This works (in C# 4.0 at least - not tried in earlier versions):
这有效(至少在 C# 4.0 中 - 在早期版本中未尝试过):
SomeDelegate a = Inc;
Func<int, int> c = new Func<int, int>(a);
If you look at the IL, this compiles into exactly the same code as Winston's answer. Here's the IL for the second line of what I just wrote:
如果您查看 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)
And that's also precisely what you see if you assign a.Invoke
into c
.
如果您将其分配a.Invoke
到c
.
Incidentally, although Diego's solution is more efficient, in that the resulting delegate refers directly to the underlying method rather than going through the other delegate, it doesn't handle multicast delegates correctly. Winston's solution does, because it just defers completely to the other delegate. If you want a direct solution that also handles delegates with multiple targets, you need something a little more complex:
顺便说一下,虽然 Diego 的解决方案更有效,因为结果委托直接引用底层方法而不是通过另一个委托,它不能正确处理多播委托。Winston 的解决方案确实如此,因为它只是完全服从另一个委托。如果你想要一个直接的解决方案来处理具有多个目标的委托,你需要一些更复杂的东西:
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;
}
This does the right thing for delegates with a single target by the way—it will end up producing just a single delegate of the target type that refers directly to whatever method (and where applicable, object) the input delegate referred to.
顺便说一下,这对于具有单个目标的委托来说是正确的——它最终只会产生一个目标类型的委托,该委托直接引用输入委托所引用的任何方法(以及适用的对象)。
回答by Lucas Meijer
You can hack a cast by using a trick where you use the c# equivalent of a c++ union. The tricky part is the struct with two members that have a [FieldOffset(0)]:
您可以通过使用与 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);
}
}
回答by tymtam
I like examples. Here is my example code:
我喜欢例子。这是我的示例代码:
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();
}
}
The output is:
输出是: