Reputation: 848
I am trying to check if a result, which I downcast in the return type is convertible to which derived type. The derived type I am checking against is a generic with a covariant argument. I am using the is operator to cast it to a dynamic type. I believe since the generic argument is a primitive type bool that it is not working. Strangely in the watch window the result is as expected, but the code execution is not. I'm not sure if there is something i'm missing or this is a bug. Is this expected behavior?
I have worked around this by checking if the result is a generic and then getting the type argument and using MakeGenericType combined with a 'dynamic result = Convert.ChangeType'.
Here is a simple sample application to demonstrate.
var testBool = new List<bool>(); // Primitive
var testString = new List<string>(); // Class
if (testBool is IEnumerable<bool>)
Console.WriteLine("Test Bool");
if (testBool is IEnumerable<dynamic>)
Console.WriteLine("Test Bool - Dynamic");
if (testString is IEnumerable<string>)
Console.WriteLine("Test string");
if (testString is IEnumerable<dynamic>)
Console.WriteLine("Test string - Dynamic");
Notes: .NET Core 2.1, Visual Studio 2017, C#
Upvotes: 2
Views: 533
Reputation: 1503954
dynamic
doesn't exist at execution time as a distinct type. Dynamic typing is performed by the C# compiler in conjunction with some very cunning framework features. The runtime doesn't know about it at all though.
You're effectively asking whether testBool
implements IEnumerable<object>
- and it doesn't. (That's what the IL involved is testing for.)
There is a bug, but it's in the Watch window handling - not in the regular execution. I've seen various situations where the Watch window doesn't quite behave like regular code. I wouldn't be surprised if this was particularly acute around dynamic
.
In terms of the behaviour of the List<string>
:
List<string>
implements IEnumerable<dynamic>
due to the covariance of IEnumerable<T>
(i.e. it implements IEnumerable<object>
)List<string>
doesn't implement IList<dynamic>
, as just one example where there's no variance involved.If you were thinking that using dynamic
as a type argument would effectively check "does this type implement IEnumerable<T>
for some type T
which will be determined dynamically", it doesn't. You can use dynamic
to perform execution-time type inference though:
dynamic d = ...; // Whatever value you're interested in
ShowList(d);
private void ShowList<T>(IEnumerable<T> list)
{
Console.WriteLine($"Implements IEnumerable<{typeof(T)}>");
}
private void ShowList(object backstop)
{
Console.WriteLine("I guess it doesn't implement IEnumerable<T> at all");
}
Note that this sort of thing can be dangerous if you're dealing with entirely unknown values - if you try this with a value that implements (say) IEnumerable<string>
and IEnumerable<bool>
, an exception will be thrown in the same way that you'd get a compile-time error trying to call ShowList
with that value, as type inference doesn't find a "best" T
.
Upvotes: 5