saravanan
saravanan

Reputation: 408

C# Dynamic casting surpasses the type mismatch error for a different parameter

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

Answers (2)

Jasper Kent
Jasper Kent

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

Jon Skeet
Jon Skeet

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

Related Questions