我正在使用反射来抓取恰好是委托的字段。我需要用自己的委托替换这个委托,但委托的类型是私有的(所以我不能从我的方法创建它并分配它)
我有一个具有完全匹配签名的委托类型,所以有什么方法可以动态地将我的委托转换为另一种类型吗?我有一个表示未知类型的Type对象。
我意识到我上面所说的可能不太清楚,所以这里有一些代码:
var delegate_type = Assembly.GetAssembly(typeof(A.F))
// public delegate in A.ZD (internal class)
.GetType("A.ZD+WD");
A.ZD+WS
(模糊名称)委托的类型签名为void(System.Drawing.Graphics)
。
我是否可以将Action<Graphics>
转换为此委托类型?
答案 0 :(得分:5)
This article似乎有你想要的东西。
答案 1 :(得分:3)
它仅适用于附加到托管方法的代理。 如果试图将Mike的文章用于与GetDelegateForFunctionPointer附加到非托管dll函数的委托,那么CreateDelegate技术将返回一个空附件,因此会调用uppon。 在这种情况下,我看到了一种通过使用包装类绕过转换问题的方法。抽象类有这个接口的地方:
public abstract class IInvokable
{
public abstract T Call0<T>();
public abstract T Call1<T, T2>(T2 arg);
public abstract T Call2<T, T2, T3>(T2 arg1, T3 arg2);
public abstract void SetDelegate(Delegate thedel);
public abstract Type GetDelegateType();
}
然后,必须修改您获得委托的程序集,以使用IInvokable中的类包装实际委托。 例如:
class Invokable : IInvokable
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int SomeDelegateTypeReturningIntTakingVoid();
public override Type GetDelegateType()
{
return typeof(SomeDelegateTypeReturningIntTakingVoid);
}
public override void SetDelegate(Delegate thedel)
{
mydelegate = (SomeDelegateTypeReturningIntTakingVoid)thedel;
}
public SomeDelegateTypeReturningIntTakingVoidmydelegate;
public override T Call0<T>()
{
return (T)(Object)mydelegate();
}
public override T Call1<T, T2>(T2 arg)
{
throw new ArgumentException("this delegate is a Call0<int>");
}
public override T Call2<T, T2, T3>(T2 arg1, T3 arg2)
{
throw new ArgumentException("this delegate has a Call0<int>");
}
}
此时类型必须完全“硬编码”,这意味着不能使用Func,因为它会阻止使用GetDelegateForFunctionPointer,因为该函数的愚蠢限制(不能用于泛型,因为MS团队不称职基本上,cf msdn forums for the source on that)。
我解决这个问题的方法是使用:Type GenerateDynamicType(string sourceCode, string typenameToGet)
{
var cp = new System.CodeDom.Compiler.CompilerParameters
{
GenerateInMemory = true, // you will get a System.Reflection.Assembly back
GenerateExecutable = false, // Dll
IncludeDebugInformation = false,
CompilerOptions = ""
};
var csharp = new Microsoft.CSharp.CSharpCodeProvider();
// this actually runs csc.exe:
System.CodeDom.Compiler.CompilerResults cr =
csharp.CompileAssemblyFromSource(cp, sourceCode);
// cr.Output contains the output from the command
if (cr.Errors.Count != 0)
{
// handle errors
throw new InvalidOperationException("error at dynamic expression compilation");
}
System.Reflection.Assembly a = cr.CompiledAssembly;
// party on the type here, either via reflection...
Type t = a.GetType(typenameToGet);
return t;
}
在StackOverflow上的另一个答案中找到。 并动态生成各种Invokable的代码。使用:
创建实例IInvokable inv = (IInvokable)Activator.CreateInstance(GenerateDynamicType(...));
最后一个非常复杂的系统。谢谢你,MS真的很懒。