mbursill
mbursill

Reputation: 3151

Casting interface type in Lazy<T>

I want something like this:

public interface IAnimal
{ }

public class Dog : IAnimal
{
    public Dog() {}
}

public class Cat : IAnimal
{
    public Cat() {}
}

public abstract class TestClassBase
{
    public TestClassBase()
    {
        _lazyAnimal = CreateLazyAnimal();
    }

    private Lazy<IAnimal> _lazyAnimal = null;
    public IAnimal Animal
    {
        get
        { 
            IAnimal animal = null;
            if (_lazyAnimal != null)
                animal = _lazyAnimal.Value;

            return animal;
        }
    }

    // Could be overridden to support other animals
    public virtual Lazy<IAnimal> CreateLazyAnimal()
    {
        // default animal is a dog
        return new Lazy<Dog>(); // this type of casting doesn't work and I don't know a good workground
    }
}

I know from tinkering with MEF that it manages to find and store different types, implementing a single interface, into Lazy<T>. Just not sure how to do it myself.

Upvotes: 16

Views: 6422

Answers (2)

Tomas Petricek
Tomas Petricek

Reputation: 243061

Casting Lazy<Dog> to Lazy<IAnimal> is not allowed because the types are different (the Lazy<T> type inherits just from object). In some cases, the casting can make sense - for example casting IEnuerable<Dog> to IEnumerable<IAnimal>, but the casting isn't safe in all cases.

C# 4.0 adds support for this casting in the safe case. It is called covariance and contravariance. For example, this article gives a nice overview.

Unfortunatelly, in C# 4.0 this works only for interfaces and delegates and not for concrete classes (e.g. Lazy<T>). You could probably solve the problem by creating interface ILazy<out T> and a wrapper for standard Lazy type, but it is probably easier to just write conversion from Lazy<Dog> to Lazy<IAnimal>.

Upvotes: 9

Bradley Grainger
Bradley Grainger

Reputation: 28182

Lazy<Dog> cannot be converted directly to Lazy<IAnimal>, but since Dog can be converted to IAnimal you can use the Lazy<IAnimal> constructor overload that expects an IAnimal (strictly speaking, it takes a Func that returns an IAnimal) and provide a Dog instead:

    public virtual Lazy<IAnimal> CreateLazyAnimal()
    {
        // default animal is a dog
        return new Lazy<IAnimal>(() => new Dog());
    }

Upvotes: 21

Related Questions