Christian
Christian

Reputation: 7852

How to filter a collection of delegates based on their parameter's generic type in C#?

I have a collection of delegates:

IList<Action<ISomeInterface>> _delegates = new List<Action<ISomeInterface>>();

And a method* to add delegates to it**:

public void AddDelegate<T>(Action<T> del) where T : ISomeInterface
{
    _delegates.Add(si => del((T)si));   
}

Now I want to filter the delegates collection based on the concrete type the delegate is constructed with:

var aDelegates = _delegates.Where(d => d is Action<SomeInterfaceImplA>);
foreach(var del in aDelegates)
{
   ....
}

Which will return all delegates, not only Action<SomeInterfaceImplA> delegates. So my question is, what predicate should be used in the Where clause to get the correct subset from the filtering? Full code example is available here.
* A fluent API (generic) method is using it hence the use of a generic type here
** Based on the answer here

Upvotes: 0

Views: 585

Answers (2)

Alex
Alex

Reputation: 13224

I am not sure that the construction you have currently makes any sense. You may want to change what you are doing if you want to filter your delegates by concrete expected implementation argument type, by changing this:

IList<Action<ISomeInterface>> _delegates = new List<Action<ISomeInterface>>();

to this:

IDictionary<Type, List<Action<ISomeInterface>>> _delegates = 
    new Dictionary<Type, List<Action<ISomeInterface>>>();

And the AddDelegate method to

public void AddDelegate<T>(Action<T> del) where T : ISomeInterface
{
    var list = default(List<Action<ISomeInterface>>);
    if (!_delegates.TryGetValue(typeof(T), out list))
        _delegates[typeof(T)] = list = new List<Action<ISomeInterface>>();
     list.Add(si => del((T)si));   
}

And use the dictionary to filter by argument type.

The reason why your current code will not work, is that all of the registered actions are actually of type Action<ISomeInterface>, that their method body (si => del((T)si) performs a dangerous cast of its argument to a type T does not change that.

Upvotes: 1

Phil Gref
Phil Gref

Reputation: 987

This not be the prettiest thing ever, but it works

    var aDelegates = someClass.Delegates.Where(d => 
        d.Method.DeclaringType.GenericTypeArguments.FirstOrDefault().IsAssignableFrom(typeof(SomeInterfaceImplA)));

Upvotes: 1

Related Questions