动态地将一个委托类型转换为另一个委托类型

3

我正在使用反射来获取一个字段,该字段恰好是委托。我需要用自己的委托替换这个委托,但委托的类型是私有的(因此我无法从我的方法创建它并分配它)

我有一个与签名完全匹配的委托类型,那么有没有办法将我的委托动态转换为这种其他类型?我有一个表示未知类型的 Type 对象。

我意识到我上面说的可能不太清楚,所以这里有一些代码:

var delegate_type = Assembly.GetAssembly(typeof(A.F))
    // public delegate in A.ZD (internal class)
    .GetType("A.ZD+WD");
< p > A.ZD+WS(混淆名称)委托的类型签名是void(System.Drawing.Graphics)

我是否可以将Action<Graphics>强制转换为此委托类型?


这篇文章似乎对OP有用:http://code.logos.com/blog/2008/07/casting_delegates.html - cs95
1个回答

3

这个方法只适用于绑定到托管方法的委托。如果尝试使用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,    // 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上找到了另一个答案。

并且动态地为各种可调用对象生成代码。使用以下方法创建实例:

IInvokable inv = (IInvokable)Activator.CreateInstance(GenerateDynamicType(...));

最终是一个非常复杂的系统。感谢微软如此懒惰,真的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接