2010-08-28 42 views
2

我正在使用反射來抓取碰巧是委託的字段。我需要用我自己的替換這個委託,但委託類型是私人的(所以我不能從我的方法創建它,並分配它)將一種類型的代理動態投射到另一個代理

我有一個委託類型完全匹配的簽名,所以是有一些方法可以動態地將我的委託轉換爲其他類型?我有一個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>轉換爲此委託類型?

回答

6

This article似乎有你想要的。

+0

謝謝,工作過! – 2010-08-28 08:27:07

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類inherting來包裝實際委託。 例如:

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上其他的答案中。 ,併爲各種可運行的程序生成代碼。創建實例使用:

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

到底是一個非常複雜的系統。謝謝你MS真的很懶惰。

相關問題