代码之家  ›  专栏  ›  技术社区  ›  anonymous coward

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

  •  3
  • anonymous coward  · 技术社区  · 14 年前

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

    我有一个具有完全匹配的签名的委托类型,那么有什么方法可以将我的委托动态地强制转换为另一个类型吗?我有一个表示未知类型的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> 到这个委托类型?

    2 回复  |  直到 14 年前
        1
  •  3
  •   Lightness1024    12 年前

    它仅适用于附加到托管方法的委托。 如果试图使用Mike的文章对带有GetDelegateForFunctionPointer的非托管dll函数附加的委托进行处理,那么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();
    }
    

    例如:

    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团队基本上是不称职的,c.f.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;
    }
    

    并为各种可调用的动态对象生成代码。创建实例时使用:

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

    最后是一个非常复杂的系统。谢谢你这么懒,真的。