Динамическое приведение одного типа делегата к другому - PullRequest
3 голосов
/ 28 августа 2010

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

У меня есть тип делегата с точно совпадающей подписью,так есть ли способ, которым я могу динамически привести мой делегат к этому другому типу?У меня есть объект 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 ]

5 голосов
/ 28 августа 2010

Эта статья , кажется, имеет то, что вы хотите.

3 голосов
/ 13 декабря 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...