none
Generic compile problem RRS feed

  • Question

  • Hi,

    Can somebody explain me why the following code doesn't compile using the .NET 2.0 compiler.


    1public interface ISomeInterface 
    2
    3    void MyMethod(); 
    4
    5public class MyClass : ISomeInterface 
    6
    7    public MyClass() 
    8    { } 
    9 
    10    public T GetProperty<T>() 
    11    { 
    12        if (typeof(T) == typeof(ISomeInterface)) 
    13            return (T)this
    14 
    15        return default(T); 
    16    } 
    17 
    18    public void MyMethod() 
    19    { } 
    20}

    I'm getting the compile error "Cannot convert type 'MyClass' to 'T' on line 13. It does work when I first convert this to an object like so "return (T)(object)this;".

    Kind regards,

    Alex.




    Thursday, January 29, 2009 2:33 PM

Answers

  • The compiler has no way of knowing that T is compatible with MyClass (or ISomeInterface for that matter). In order to cast, the compiler has to do an "IsAssignableFrom" check on the type, but there's no guarantee that MyClass is polymorphic with T. This is because T is a "naked" type parameter. For example, what if the calling code specified T = Int32? The cast "(Int32)this" would be completely invalid. It doesn't matter that you are doing a runtime check above it - the simple fact is that the code (Int32)this would never compile and that's what it's complaining about.

    However, since all classes inherit from Object, it is safe to cast Object as T (in other words, no matter what T is, it will support the Object interface). Note that it would work for you situation here based on the logic you provided, but in a more generalized point of view, the assignment might fail at runtime had it been different. If you want more info, check out the Generic Constraints section in help.


    -Rob Teixeira
    • Proposed as answer by rtizan[0] Thursday, January 29, 2009 6:24 PM
    • Marked as answer by Ji.ZhouModerator Friday, January 30, 2009 1:30 PM
    Thursday, January 29, 2009 6:04 PM

All replies

  • The compiler has no way of knowing that T is compatible with MyClass (or ISomeInterface for that matter). In order to cast, the compiler has to do an "IsAssignableFrom" check on the type, but there's no guarantee that MyClass is polymorphic with T. This is because T is a "naked" type parameter. For example, what if the calling code specified T = Int32? The cast "(Int32)this" would be completely invalid. It doesn't matter that you are doing a runtime check above it - the simple fact is that the code (Int32)this would never compile and that's what it's complaining about.

    However, since all classes inherit from Object, it is safe to cast Object as T (in other words, no matter what T is, it will support the Object interface). Note that it would work for you situation here based on the logic you provided, but in a more generalized point of view, the assignment might fail at runtime had it been different. If you want more info, check out the Generic Constraints section in help.


    -Rob Teixeira
    • Proposed as answer by rtizan[0] Thursday, January 29, 2009 6:24 PM
    • Marked as answer by Ji.ZhouModerator Friday, January 30, 2009 1:30 PM
    Thursday, January 29, 2009 6:04 PM
  • You'll have to give some minimal guarantees that the cast is feasible and can be expressed generically.  That requires excluding value types since their casts invoke special conversions.  Do it like this:

        public T GetProperty<T>() where T : class {
          if (typeof(T) == typeof(ISomeInterface))
            return this as T;
          return default(T);
        }
    Hans Passant.
    Friday, January 30, 2009 1:32 AM
    Moderator