Search code examples
c#generic-variance

Can C# 4.0 variance help me call a base class constructor with an upcast?


I was reading a bit on generic variance and I don't have a full understanding of it yet but I'd like to know if it makes something like the following possible?

class A<T> { }

class B { }

class C : B { }

class My1  {
    public My1(A<B> lessDerivedTemplateParameter)
    {
    }
}

class My2 : My1 {
    public My2(A<C> moreDerivedTemplateParameter)
        : base(moreDerivedTemplateParameter) // <-- compile error here, cannot convert
    {
    }
}

Solution

  • No, because while C inherits from B, A<C> does not inherit from A<B>.

    To understand why this is the case, imagine if A<T> were instead List<T>:

    class B { }
    
    class C : B { }
    
    class D : B { }
    
    class My1  {
        public My1(List<B> lessDerivedTemplateParameter)
        {
           // This is totally legal
           lessDerivedTemplateParameter.Add(new D());
        }
    }
    
    class My2 : My1 {
        public My2(List<C> moreDerivedTemplateParameter)
            // if this were allowed, then My1 could add a D to a list of Bs
            : base(moreDerivedTemplateParameter)
        {
        }
    }
    

    Now on the other hand, this is legal:

    interface IA<out T> { 
        public T GetSome();
    }
    
    class B { }
    
    class C : B { }
    
    class D : B { }
    
    class My1  {
        public My1(IA<B> lessDerivedTemplateParameter)
        {
           // This is totally legal
           var someB = lessDerivedTemplateParameter.GetSome();
        }
    }
    
    class My2 : My1 {
        public My2(IA<C> moreDerivedTemplateParameter)
            // This is allowed, because an A<C> only *produces* C's (which are also B's)
            // so the base class (which consumes B's, and doesnt care if they are C's) 
            // can use an IA<C>
            : base(moreDerivedTemplateParameter)
        {
        }
    }