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)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With