2010-08-28 2 views
2

Я использую отражение, чтобы захватить поле, которое является делегатом. Мне нужно заменить этот делегат на свой собственный, но тип делегата является приватным (поэтому я не могу создать его из своего метода и назначить его)Динамическое литье одного типа делегата другому

У меня есть тип делегата с точно подобранной подписью, поэтому каким-то образом я могу динамически отдать мой делегат этому другому типу? У меня есть объект типа, представляющий неизвестный тип.

Я понимаю, что я сказал выше, возможно, не очень понятно, так вот некоторый код:

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

Спасибо, обработано! –

3

Он работает только для делегатов, подключенных к управляемым методам. Если вы попытаетесь использовать статью Майка для делегата, прикрепленного к неуправляемой функции 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(); 
} 

Затем узел вы получите ваш делегат от должен быть изменен, чтобы обернуть фактический делегат с классом inherting от 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, из-за тупого ограничение этой функции (не может работать с generics, потому что команда MS некомпетентна в основном, cf 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 за то, что вы так ленивы.

Смежные вопросы