Reputation: 3151
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
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
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