Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Storing and calling generically-typed delegates

What I'm looking for is probably not going to be possible without resorting to reflection. If that's the case, I'd still want to know the best way to pull it off.

Essentially, this is what I want my code to look like:

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

My question is, how can I store these delegates, each with a different signature, in a list in MyClass? And how can I call them later on when I want to, using the return value from each one as the input parameter to the next one?

The inside of MyClass may very well be a mess of List's and all that. But I'm not even sure where to start on this.

(Originally, I wanted to call new MyClass<int, string, Warehouse, IList<Supplier>>(). However, since there's no "type parameter array", I gave up on that approach.)

like image 718
Elliot Nelson Avatar asked Feb 01 '12 18:02

Elliot Nelson


People also ask

Can delegates be used with generic types?

Delegates defined within a generic class can use the generic class type parameters in the same way that class methods do. Generic delegates are especially useful in defining events based on the typical design pattern because the sender argument can be strongly typed and no longer has to be cast to and from Object.

What is generic delegate?

Func is generic delegate present in System namespace. It takes one or more input parameters and returns one out parameter. The last parameter is considered as a return value. Func delegate type can include 0 to 16 input parameters of different types. It must have one return type.

How do you declare a generic delegate?

You can define a Generic delegate with type parameters. delegate T numbermanipulat<T>(T var); T is the generic type parameter that allows you to specify an arbitrary type (T) to a method at compile time without specifying a collection type in the method or class declaration.

What is generic type in C#?

Generic means the general form, not specific. In C#, generic means not specific to a particular data type. C# allows you to define generic classes, interfaces, abstract classes, fields, methods, static methods, properties, events, delegates, and operators using the type parameter and without the specific data type.


2 Answers

Well, you could store them all as Delegate - but the tricky thing is invoking them later.

If you're able to validate that the next delegate at any time is of the right type, e.g. by holding a Type reference for "the current output" you could always store a List<Func<object, object>> and make your Add method something like:

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);
}

Then to invoke them all:

object current = ...; // Wherever
foreach (var func in list)
{
    current = func(current);
}
like image 129
Jon Skeet Avatar answered Nov 03 '22 22:11

Jon Skeet


The Linq Select statement essentially does this...

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

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

You can also store each intermediate Select call as an Enumerable to have the stated method you use in the OP.

like image 39
Servy Avatar answered Nov 03 '22 22:11

Servy