Хранение и вызов делегатов общего типа - PullRequest
9 голосов
/ 01 февраля 2012

То, что я ищу, вероятно, не будет возможно без обращения к размышлению.Если бы это было так, я все еще хотел бы знать, как лучше всего это осуществить.

По сути, я хочу, чтобы мой код выглядел так:

var instance = new MyClass();
instance.Add<int, string>(x => x.ToString());
instance.Add<string, Warehouse>(x => Warehouse.LookupByName(x));
instance.Add<Warehouse, IList<Supplier>>(x => x.Suppliers());

instance.Chain(3);    // should call each lambda expression in turn

Мой вопростакое, как я могу сохранить эти делегаты, каждый с разной подписью, в списке в MyClass?И как я могу вызвать их позже, когда захочу, используя возвращаемое значение каждого из них в качестве входного параметра для следующего?

Внутри MyClass вполне может быть беспорядок List и все такое,Но я даже не уверен, с чего начать.

(Изначально я хотел вызвать new MyClass<int, string, Warehouse, IList<Supplier>>(). Однако, поскольку «массива параметров типа» нет, я отказался от этого подхода.)

Ответы [ 4 ]

11 голосов
/ 01 февраля 2012

Что ж, вы могли бы сохранить их все как Delegate - но хитрая вещь вызывает их позже.

Если вы можете проверить, что следующий делегат в любое времяимеет правильный тип, например, удерживая ссылку Type для «текущего выхода», вы всегда можете сохранить List<Func<object, object>> и сделать свой метод Add что-то вроде:

public void Add<TIn, TOut>(Func<TIn, TOut> func)
{
    // TODO: Consider using IsAssignableFrom etc
    if (currentOutputType != typeof(TIn))
    {
        throw new InvalidOperationException(...);
    }
    list.Add(o => (object) func((TIn) o));
    currentOutputType = typeof(TOut);
}

Затем вызватьих все:

object current = ...; // Wherever
foreach (var func in list)
{
    current = func(current);
}
2 голосов
/ 01 февраля 2012

Оператор Linq Select по существу делает это ...

var temp = instance.Select(x => x.ToString())
.Select(x => WareHouse.LookupByName(x))
.Select(x=> x.Suppliers());

List<List<Suppliers>> = temp.ToList(); //Evaluate statements

Вы также можете сохранить каждый промежуточный вызов Select как Enumerable, чтобы иметь указанный метод, который вы используете в OP.

0 голосов
/ 01 февраля 2012

Если вы хотите проверить тип времени компиляции, то, что вы делаете, звучит подозрительно, как простые старые универсальные делегаты. Предполагая, что есть некоторая ценность для хранения отдельных функций, которые были Add ed (кроме преобразования Int в String) и их составления позже, вы можете сделать что-то вроде этого:

var lookupWarehouseByNumber = new Func<int, Warehouse>(i => Warehouse.LookupByName(i.ToString()));
var getWarehouseSuppliers = new Func<Warehouse, IEnumerable<Supplier>>(w => w.Suppliers);
var getWarehouseSuppliersByNumber = new Func<int, IEnumerable<Supplier>>(i => getWarehouseSuppliers(lookupWarehouseByNumber(i)));
0 голосов
/ 01 февраля 2012
class Program
{
    static void Main(string[] args)
    {
        var instance = new MyClass();
        instance.Add<int, string>(i => i.ToString());
        instance.Add<string, int>(str => str.Length);
        instance.Add<int, int>(i => i*i);

        Console.WriteLine(instance.Chain(349));
        Console.ReadLine();

    }
}

public class MyClass
{
    private IList<Delegate> _Delegates = new List<Delegate>();

    public void Add<InputType, OutputType>(Func<InputType, OutputType> action)
    {
        _Delegates.Add(action);
    }

    public object Chain<InputType>(InputType startingArgument)
    {
        object currentInputArgument = startingArgument;
        for (var i = 0; i < _Delegates.Count(); ++i)
        {
            var action = _Delegates[i];
            currentInputArgument = action.DynamicInvoke(currentInputArgument);
        }
        return currentInputArgument;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...