Есть ли способ получить действие, принимающее любой тип в качестве единственного параметра от делегата? - PullRequest
0 голосов
/ 25 марта 2019

Я создаю Delegate из метода, который, как я знаю, принимает только один параметр, а затем вызываю его, используя DynamicInvoke, но мне было интересно, можно ли было заставить Action вызывать напрямую.

Вот что у меня сейчас:

private IEnumerable<MethodInfo> GetMethods()
            => GetType().GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

private IEnumerable<Thing> GetThings() {
    foreach (var method in GetMethods()) {
        var attribute = (MyAttribute) method.GetCustomAttribute(typeof(MyAttribute), false);
        var theDelegate = CreateDelegate(method);

        return new Thing(attribute.Name, theDelegate);
    }
}

private Delegate CreateDelegate(MethodInfo method) {
    Type requestType = method.GetParameters()[0].ParameterType,
         actionType = typeof(Action<>).MakeGenericType(requestType);

    return Delegate.CreateDelegate(actionType, this, method);
}

public void Invoke(Thing thing, string json) {
    var requestType = MyDelegate.Method.GetParameters()[0].ParameterType;
    var o = Deserialize(json, requestType);

    thing.TheDelegate.DynamicInvoke(o);
}

Используя Действие, не только будет быстрее, но и намного лучше . Следующий код не работает , но должен быть способ получить что-то похожее:

private Action CreateAction(MethodInfo method) {
    Type requestType = method.GetParameters()[0].ParameterType,
         actionType = typeof(Action<>).MakeGenericType(requestType);

    return (Action) Delegate.CreateDelegate(actionType, this, method);
}

public void Invoke(Thing thing, string json) {
    Type requestType = MyAction.GetParameters()[0].ParameterType;
    var o = Deserialize(json, requestType);

    thing.MyAction(o);
}

Ответы [ 3 ]

0 голосов
/ 25 марта 2019

Если вы посмотрите на справочный источник , вы увидите следующие строки:

public delegate void Action<in T>(T obj); 
public delegate void Action(); 

Action и Action<T> являются делегатами, поэтому я не вижу причин, почему это должно происходить быстрее.

Но что более важно: ваш код не может работать, потому что Action просто не равен Action<T>, он не принимает параметр. Они оба происходят от Delegate, но не друг от друга.

0 голосов
/ 25 марта 2019

Поскольку мы не знаем точно, откуда ваш CreateDelegate метод получает MethodInfo, я предполагаю, что у вас есть прямой доступ к правильному методу. Таким образом, с помощью следующего класса мы можем кэшировать делегата, который вызывается с string из json.

public sealed class JsonInvoker<T>
{
    private readonly Action<T> _action;

    public JsonInvoker(Action<T> action)
    {
        _action = action;
    }

    public void Invoke(string json)
    {
        var arg = Deserialize(json);
        _action(arg);
    }

    private T Deserialize(string json) => //...
}

Затем настройте свой класс поддержки.

private readonly JsonInvoker<DataClass> _dataClassInvoker = 
    new JsonInvoker<DataClass>(DataClass.Process); // Pass the relevant method
0 голосов
/ 25 марта 2019

Поскольку Action<T> не является производным от Action, вы не можете присвоить Action<T> для Action. Но оба они происходят от Delegate, поэтому вы можете назначить их на Delegate.

Боюсь, что вам придется придерживаться Delegate в качестве типа возврата.

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