Reputation: 9015
This code:
public interface IInter { }
public class Concrete : IInter { /*... body ...*/ }
var t = (List<IInter>)new List<Concrete>();
Yields this error:
Cannot convert type 'System.Collections.Generic.List<Concrete>' to 'System.Collections.Generic.List<IInter>'
Why is it ? how do I overcome it ? my goal is this:
var t = new List<List<IInter>>()
{
new List<ConcreteA>(){/* ... data ... */},
new List<ConcreteB>(){/* ... data ... */},
// ...
new List<ConcreteX>(){/* ... data ... */},
};
Thanks for all your help. Ahh, I kinda abstracted things, to make it easier to read... but my real problem is this:
public class SingletonFactory<T> where T : IToken
{
private SingletonFactory() { }
private static SingletonFactory<T> _instance = new SingletonFactory<T>();
public static SingletonFactory<T> Instance { get { return _instance; } }
public T Produce(int position) { return (T)Activator.CreateInstance(typeof(T), position); }
public T Produce(int position, string token) { return (T)Activator.CreateInstance(typeof(T), position, token); }
}
And then:
var keywords = new Dictionary<string, SingletonFactory<IToken>>()
{
{ "abc", SingletonFactory<Abc>.Instance },
{ "xyz", SingletonFactory<Xyz>.Instance },
{ "123", SingletonFactory<Num>.Instance }
};
So I guess it's much more complicated...
I'm using c# 4.0
Upvotes: 1
Views: 269
Reputation: 2596
Make a covrariant interface for the methods you need to access from SingletonFactory<T>
. This will ensure that your type T is output type safe.
public interface IToken { }
public class Abc : IToken { }
public class Xyz : IToken { }
public class Num : IToken { }
public interface ISingletonFactory<out T> where T : IToken
{
T Produce(int position);
T Produce(int position, string token);
}
public class SingletonFactory<T> : ISingletonFactory<T> where T : IToken
{
private SingletonFactory() { }
private static SingletonFactory<T> _instance = new SingletonFactory<T>();
public static SingletonFactory<T> Instance { get { return _instance; } }
public T Produce(int position) { return (T)Activator.CreateInstance(typeof(T), position); }
public T Produce(int position, string token) { return (T)Activator.CreateInstance(typeof(T), position, token); }
}
var keywords = new Dictionary<string, ISingletonFactory<IToken>>()
{
{ "abc", SingletonFactory<Abc>.Instance },
{ "xyz", SingletonFactory<Xyz>.Instance },
{ "123", SingletonFactory<Num>.Instance }
};
Upvotes: 1
Reputation: 38580
This is called covariance and C# supports covariance (and contravariance) on generic interfaces and not generic classes. This is the following works but your example does not:
IEnumerable<IInter> e = new List<Concrete>();
ICollection<IInter> c = new List<Concrete>();
Covariance is also supported on arrays:
IInter[] a = new Concrete[3];
Upvotes: 2
Reputation: 17580
One way is:
IEnumerable<IInter> t = new List<Concrete>();
Another is:
List<IInter> t = new List<Concrete>().ConvertAll(x => (IInter) x);
Edit, adding better sample to show that it works (the test passes):
[Test]
public void CovarianceTest()
{
var concrete = new Concrete();
IEnumerable<IInter> t = new List<Concrete> { concrete };
Assert.IsTrue(new[] { concrete }.SequenceEqual(t));
List<IInter> t2 = new List<Concrete> { concrete }.ConvertAll(x => (IInter)x);
Assert.IsTrue(new[] { concrete }.SequenceEqual(t2));
}
Upvotes: 1
Reputation: 152501
Because you cannot assign a List<ConcreteA>
to a List<IInter>
, otherwise you could do this:
concreteAList = newList<ConcreteA>();
List<Inter> interList = concreteAList as List<Inter>; // seems harmless
interList.Add(new ConcreteB()); // not allowable
You could do:
var t = new List<List<IInter>>()
{
new List<IInter>(){/* ... fill with ConcreteAs ... */},
new List<IInter>(){/* ... fill with ConcreteBs ... */},
// ...
new List<IInter>(){/* ... fill with ConcreteXs ... */},
};
But I don't know if that accomplishes what you want.
Upvotes: 2
Reputation: 460038
A List<Concrete>
is not a List<IInter>
although Concrete
implements IInter
.
You can use:
List<IInter> t = ConcreteList.Cast<IInter>().ToList();
Covariance and Contravariance FAQ
Upvotes: 2