这个方法只适用于绑定到托管方法的委托。如果尝试使用Mike的文章来绑定到未管理的dll函数的委托,使用GetDelegateForFunctionPointer,则CreateDelegate技术将返回空附件,并在调用时崩溃。在这种情况下,我看到一种通过使用包装类来绕过强制转换问题的方式。其中抽象类具有以下接口:
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,因为该函数有一个愚蠢的限制(不能与泛型一起使用,因为微软团队基本上是无能的,可以参考msdn论坛了解源代码)。
我的解决方案是使用:
Type GenerateDynamicType(string sourceCode, string typenameToGet)
{
var cp = new System.CodeDom.Compiler.CompilerParameters
{
GenerateInMemory = true,
GenerateExecutable = false,
IncludeDebugInformation = false,
CompilerOptions = ""
};
var csharp = new Microsoft.CSharp.CSharpCodeProvider();
System.CodeDom.Compiler.CompilerResults cr =
csharp.CompileAssemblyFromSource(cp, sourceCode);
if (cr.Errors.Count != 0)
{
throw new InvalidOperationException("error at dynamic expression compilation");
}
System.Reflection.Assembly a = cr.CompiledAssembly;
Type t = a.GetType(typenameToGet);
return t;
}
这里在StackOverflow上找到了另一个答案。
并且动态地为各种可调用对象生成代码。使用以下方法创建实例:
IInvokable inv = (IInvokable)Activator.CreateInstance(GenerateDynamicType(...));
最终是一个非常复杂的系统。感谢微软如此懒惰,真的。