Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# How to pass generic enumerable type parameter to another method expecting an IEnumerable?

Tags:

c#

I have a method that accepts a basic generic variable in the method signature:

public void Foo<T>(T val) {

    if (val is IEnumerable) {
        Bar(val)
    }
}

...Logic if not enumerable

The signature for Bar looks like this:

private void Bar<T>(IEnumerable<T> vals) {
    ...Logic if enumerable
}

The logic is very lengthy and different based on whether the item passed in is enumerable or not. I can't get Bar(val) to work. I tried the following, let me know what I'm missing:

Bar(val)

Bar((IEnumerable<T>)val) (Compiles, but results in this error at run-time when tried with a List of ints:

Unable to cast object of type 'System.Collections.Generic.List`1[System.Int32]' to type 'System.Collections.Generic.IEnumerable`1[System.Collections.Generic.List`1[System.Int32]]'.'

Bar((IEnumerable)val)

like image 541
Brettyoke49 Avatar asked Dec 18 '25 18:12

Brettyoke49


1 Answers

The only option without changing the signature and/or using dynamic is to dive into reflection. You need to get the closed generic type of IEnumerable<TInner> (where T : IEnumerable<TInner>), construct corresponding closed version of Bar and invoke it. Something along this lines:

void Foo<T>(T val)
{
    var genericEnumInterface = typeof(T).GetInterfaces()
        .FirstOrDefault(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>));
    if (genericEnumInterface is not null)
    {
        MethodInfo mi = ...; // get Bar via reflection
        var constructedMethod = mi.MakeGenericMethod(genericEnumInterface);
        constructedMethod.Invoke(this, new[]{(object)val}); // assuming Bar is in the same class as Foo
    }
}

Note that there are types which will implement IEnumerable<T> which you possibly will not want to process via Bar like string which is IEnumerable<char>. Another concern is that reflection can cause noticable performance hit in some cases so you can try caching it (see for example this or this answer).

Also personally I would try to avoid such generic method as Foo due to possible misuse and corner cases like string.

like image 83
Guru Stron Avatar answered Dec 21 '25 11:12

Guru Stron



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!