在Lazy <T>中转换接口类型

mbu*_*ill 14 c# generics

我想要这样的东西:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道,通过修改MEF,它设法在Lazy <T>中找到并存储不同类型,实现单个接口.只是不知道如何自己做.

Bra*_*ger 18

Lazy<Dog>不能直接转换为Lazy<IAnimal>,但既然Dog可以转换为IAnimal你可以使用期望的Lazy<IAnimal> 构造函数重载IAnimal(严格来说,它需要一个Func返回一个IAnimal)并提供一个Dog代替:

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


Tom*_*cek 9

不允许转换Lazy<Dog>Lazy<IAnimal>因为类型不同(Lazy<T>类型仅从中继承object).在某些情况下,可以铸造有意义的-例如铸造IEnuerable<Dog>IEnumerable<IAnimal>,但铸造是不是在所有情况下的安全.

C#4.0在安全案例中增加了对此转换的支持.它被称为协方差和逆变.例如,本文给出了一个很好的概述.

不幸的是,在C#4.0中,这仅适用于接口和委托,而不适用于具体类(例如Lazy<T>).您可以通过创建界面可能解决问题ILazy<out T>和标准的包装Lazy类型,但它可能是更容易刚刚从写转换Lazy<Dog>Lazy<IAnimal>.