And*_*hin 43 .net c# delegates casting
我有代码:
public delegate int SomeDelegate(int p);
public static int Inc(int p) {
return p + 1;
}
Run Code Online (Sandbox Code Playgroud)
我可以投Inc
来SomeDelegate
或Func<int, int>
:
SomeDelegate a = Inc;
Func<int, int> b = Inc;
Run Code Online (Sandbox Code Playgroud)
但我不能投Inc
给SomeDelegate
和投后Func<int, int>
用这样的常用方法:
Func<int, int> c = (Func<int, int>)a; // ?ompilation error
Run Code Online (Sandbox Code Playgroud)
我怎么能这样做?
Win*_*ith 67
有一种更简单的方法可以做到这一点,所有其他答案都错过了:
Func<int, int> c = a.Invoke;
Run Code Online (Sandbox Code Playgroud)
有关详细信息,请参阅此博客文章.
dtb*_*dtb 48
SomeDelegate a = Inc;
Func<int, int> b = Inc;
Run Code Online (Sandbox Code Playgroud)
是的缩写
SomeDelegate a = new SomeDelegate(Inc); // no cast here
Func<int, int> b = new Func<int, int>(Inc);
Run Code Online (Sandbox Code Playgroud)
您无法将SomeDelegate的实例强制转换为Func <int,int>,原因与您无法将字符串强制转换为Dictionary <int,int>相同 - 它们是不同的类型.
这有效:
Func<int, int> c = x => a(x);
Run Code Online (Sandbox Code Playgroud)
这是语法糖
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);
Run Code Online (Sandbox Code Playgroud)
Die*_*hon 29
试试这个:
Func<int, int> c = (Func<int, int>)Delegate.CreateDelegate(typeof(Func<int, int>),
b.Target,
b.Method);
Run Code Online (Sandbox Code Playgroud)
问题是:
SomeDelegate a = Inc;
Run Code Online (Sandbox Code Playgroud)
实际上不是演员.这是简短的形式:
SomeDelegate a = new SomeDelegate(Inc);
Run Code Online (Sandbox Code Playgroud)
因此,没有演员.一个简单的问题解决方案可以是这个(在C#3.0中)
Func<int,int> f = i=>a(i);
Run Code Online (Sandbox Code Playgroud)
这是有效的(至少在C#4.0中 - 在早期版本中未尝试过):
SomeDelegate a = Inc;
Func<int, int> c = new Func<int, int>(a);
Run Code Online (Sandbox Code Playgroud)
如果你看一下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)
Run Code Online (Sandbox Code Playgroud)
而这也是你看到的正是如果分配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;
}
Run Code Online (Sandbox Code Playgroud)
对于具有单个目标的委托来说,这是正确的事情 - 它最终将只生成目标类型的单个委托,该委托直接引用输入委托所引用的任何方法(以及适用的对象).
您可以通过技巧来破解演员表,在技巧中使用与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);
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
20652 次 |
最近记录: |