Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
    {
    }
}
like image 274
Aaron Anodide Avatar asked May 25 '12 19:05

Aaron Anodide


People also ask

Is Can-C good for dogs?

SAFE FOR HUMANS AND DOGS - Can-C is the first and only patented NAC eye drop that uses the exact formula proven effective in both animal and human trials, offering a non-invasive alternative to cataract surgery.

What are Can C eye drops used for?

Lubricating drops for dry feeling eyes and irritation containing the potent anti-oxidant N-Acetylcarnosine (NAC), safe to be used by people with cataracts.

Can-C active ingredient?

(IVP)'s scientists developed the lubricant eye drops (Can-C) designed as 1% N-acetylcarnosine (NAC) prodrug of L-carnosine containing a mucoadhesive cellulose-based compound combined with corneal absorption promoters in a sustained drug delivery system.

What is the best eye drops for cataracts?

1 Lanosterol eye drops could potentially be a safe, non-invasive, and less costly alternative to cataract surgery for patients who have moderate forms of cataracts.


2 Answers

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)
    {
    }
}
like image 178
Chris Shain Avatar answered Oct 14 '22 12:10

Chris Shain


You can declare A as an interface with a contravariant type parameter and it will compile:

internal interface A<out T>
    {
    }

    internal class B
    {
    }

    internal class C : B
    {
    }

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

internal class My2 : My1
{
    public My2(A<C> moreDerivedTemplateParameter)
        : base(moreDerivedTemplateParameter) 
    {
    }

}
like image 27
w.brian Avatar answered Oct 14 '22 12:10

w.brian