Работает только для делегатов, которые подключены к управляемым методам.
Если попытаться использовать статью Майка для делегата, присоединенного к неуправляемой функции dll с помощью GetDelegateForFunctionPointer, то метод 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 некомпетентна в основном форумы MSDN для источника на этом).
мое решение вокруг этого заключается в использовании:
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 за то, что ты такой ленивый, правда.