Search code examples
c#.netgenericscastinggeneric-constraints

Simple Generic misunderstanding


Could you help me to understand the error in those case ?

public interface IGeneralInterface
{
}


public class A : IGeneralInterface
{
}

public class B : IGeneralInterface
{
}

public class SomeClass<TGenericType> where TGenericType : IGeneralInterface
{
    private TGenericType internalValue;

    public SomeClass(TGenericType InitValue)
    {
        internalValue = InitValue;
    }

    public TGenericType CreateAnother()
    {
       TGenericType val1 = new B();   //Error here: class B() could not be converted to TGenericType
       return val1;
    }
}

Even if I build the SomeClass<T> as

SomeClass<IGeneralInterface> someClass = new SomeClass<IGeneralInterface>();

I explicity pass base interface to include all (?) cases and it still throw an error


Solution

  • Change

     TGenericType val1 = new B();   //Error here: class B() could not be converted to TGenericType
    

    To

      IGeneralInterface val1 = new B();   
    

    You are trying to TypeCast IGeneralInterface to TGenericType which is the cause of error.

    TGenericType could have other constraints, like it inherits from ISpecificInterface from which B donot inherit. In this case the assignment becomes invalid.

    Example:

    public class SomeClass< TGenericType> where TGenericType : IGeneralInterface, ISpecificInterface
    TGenericType val1 = new B(); // TGenericType should be ISpecificInterface also, B is not.
    

    For above to run. IGenericInterface should always be more specific than TGenericType.

     public class SomeClass <IGenericInterface> 
    

    Alternatively you could use is keyword to find out whether the object is assignable to TGenericType and then use the casting.

    TGenericType val1 = default(TGenericType);
    var val = new B();
    if ( val is TGenericType)
    {
      val1 = (TGenericType)val;
    }
    

    EDIT For the below comment

    how it could at runtime have additional requirements ? Everything I put in compiler listed here

    CreateAnother() creates instance of Type B which is not generic. Take below example

    SomeClass<C> c = new SomeClass<C();
    C another = c.CreateAnother(); // C is not assignable from B. (C is below). But It would be valid, if compiler did not flag the error
    
    public class C : IGeneralInterface, IDisposable
    {
    }