Создание универсального действия типа <> во время выполнения - PullRequest
2 голосов
/ 27 июня 2011

Можно ли создать типизированное действие во время выполнения на основе некоторых указанных типов?В этом конкретном сценарии тело действия в конечном итоге будет игнорировать типы аргументов, поскольку типизированное действие <> будет просто оболочкой для действия без аргументов, например

Action original = () => { };
...
Action<TType> wrapper = (arg) => {
    original();
}

или даже:

Action<TTypeA, TTypeB> wrapper = (arg) => {
    original();
}

Как видите, тело типизированного действия <> игнорирует аргументы, а их тип - это просто оболочка.

Если вам интересно, почемуПрежде всего, я хочу создать эту обертку, «базовая» версия заключается в том, что я в конечном итоге преобразую Действие в Делегат для выполнения Delegate.Combine (), для которого требуются идентичные типы.Все, что я пытаюсь сделать с помощью Delegate.Combine () - это базовое уведомление о том, что делегат был уволен.

На этом этапе я, вероятно, переделаю свой дизайн, чтобы избежать этих типов махинаций, но явсе еще очень любопытно, как это можно сделать.

Самое близкое, что я мог получить, было следующее:

private static TType GetTypedDelegate<TType>(Action onComplete)
        where TType : class
    {
        MethodInfo info = typeof(TType).GetMethod("Invoke");
        ParameterInfo[] parameters = info.GetParameters();

        object result;
        if (parameters.Length == 0)
            result = onComplete;
        else if (parameters.Length == 1)
            result = GetTypedDelegate<TType>(onComplete, parameters[0].ParameterType);
        // etc

        TType onCompleteCasted = Delegate.CreateDelegate(typeof(TType), result, "Invoke") as TType;
        return onCompleteCasted;
    }

    private static Delegate GetTypedDelegate<TType>(Action onComplete, Type type)
    {
        // This line isn't useful for me right now, since I can't just create a new
        // instance of the action with a parameterless constructor ... but I thought I'd throw it in here in case it was of use
        Type actionType = typeof(Action<>).MakeGenericType(new[] { type });

        // Do some magic here with the type information
        // The following of course does not work,but you get the idea of what I am aiming for

        Action<type> wrapper = (arg1) =>
        {
            onComplete();
        };

        return wrapper as Delegate;
    }

Ответы [ 2 ]

1 голос
/ 27 июня 2011

Если вы не хотите использовать рефлексию, вы можете настроить некоторые классы, подобные этой.

public class ActionWrapper<TTypeA>
{
    protected readonly Action _original;
    public ActionWrapper(Action original)
    {
        _original = original;
    }
    public Action<TTypeA> Wrapped { get { return WrappedAction; } }

    private void WrappedAction(TTypeA a)
    {
        _original();
    }
}

public class ActionWrapper<TTypeA,TTypeB>:ActionWrapper<TTypeA>
{
    public ActionWrapper(Action original) : base(original)
    {
    }

    public new Action<TTypeA, TTypeB> Wrapped { get { return WrappedAction; } }

    private void WrappedAction(TTypeA a,TTypeB b)
    {
        _original();
    }
}
1 голос
/ 27 июня 2011

Я думаю, что самый простой вариант - написать универсальный метод и затем вызывать его динамически (используя Reflection или, возможно, даже используя C # 4 dynamic):

class Helper {
  public static Action<TType> Wrap1<TType>(Action arg) {
    return (arg) => { original(); }
  }
}

Вызов метода с использованием Reflection и использованиеtyp1 как аргумент универсального типа может выглядеть так:

var meth = typeof(Helper).GetMethod("Wrap1");
var gmeth = meth.MakeGenericMethod(new[] { typ1 });
var genericAction = gmeth.Invoke(null, new object[] { action });
...