Reputation: 408
When I cast a variable to type dynamic
before passing it to a generic type parameter of a function, the next parameter is bypassing the type check.
In the below snippet, how is the first call to Check
method escaping the compilation?
The (dynamic)
casting is done only to the first argument (where a Type1
is passed to Interface1
). But the second parameter where Type1
is passed to Interface2
is not failing in compilation.
interface Interface1 { }
interface Interface2 { }
class Type1 : Interface1 { }
class Type2 : Interface2 { }
class Program
{
public static void Check<T1, T2>(T1 obj1, T2 obj2) where T1 : Interface1 where T2 : Interface2
{
}
static void Main(string[] args)
{
Check((dynamic)new Type1(), new Type1()); //passes compliation and fails in runtime
Check(new Type1(), new Type1()); //fails in compilation
}
}
Upvotes: 1
Views: 401
Reputation: 3676
Using dynamic
causes the generic type checking to be deferred until runtime. Once any any parameter is dynamic
then the whole thing is deferred, so in the first statement the single dynamic
causes the deferral.
Without it, in the second statement, the checking is done at compile-time and so fails as a compiler error.
In both cases the call is invalid: obj2
cannot be of Type1
because Type1
does not implement Interface2
. It's just a question of when the error is caught.
Upvotes: 1
Reputation: 1501636
When you use any dynamic values as an argument in a method invocation, the method is dynamically bound. If you're using generic type inference at all (whether or not the dynamic value is involved in that), generic type constraints aren't validated.
Here's a slightly simpler version of what you're seeing:
using System;
class Test
{
static void Main()
{
dynamic d = 1;
// Compiles
M(d, 0);
// Doesn't compile - explicit type argument
M<int>(d, 0);
}
static void M<T>(object ignored, T value) where T : class
{
}
}
The compiler will do some checking, but it's relatively conservative in terms of what it checks. Fundamentally, if you're diving into the realm of dynamic binding, you should be really careful, and expect that things might not do as much type checking as you think it should.
(If I remember rightly, the spec is reasonably loose about exactly how much checking is performed for dynamically bound operations, so you could potentially get into a situation where it compiles with some compilers but not others.)
Upvotes: 2