如何将嵌套泛型转换为继承第一个泛型的另一个嵌套泛型
本文关键字:泛型 嵌套 第一个 另一个 继承 转换 | 更新日期: 2023-09-27 17:54:07
代码:
public interface IInter { }
public class Concrete : IInter { /*... body ...*/ }
var t = (List<IInter>)new List<Concrete>();
产生如下错误:
Cannot convert type 'System.Collections.Generic.List<Concrete>' to 'System.Collections.Generic.List<IInter>'
为什么?我该如何克服它?我的目标是:
var t = new List<List<IInter>>()
{
new List<ConcreteA>(){/* ... data ... */},
new List<ConcreteB>(){/* ... data ... */},
// ...
new List<ConcreteX>(){/* ... data ... */},
};
编辑:谢谢你的帮助。啊,我有点抽象的东西,让它更容易阅读…但我真正的问题是:
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); }
}
然后:
var keywords = new Dictionary<string, SingletonFactory<IToken>>()
{
{ "abc", SingletonFactory<Abc>.Instance },
{ "xyz", SingletonFactory<Xyz>.Instance },
{ "123", SingletonFactory<Num>.Instance }
};
所以我想这要复杂得多…
我用的是c# 4.0
var res = new List<Concrete>().Cast<IInter>().ToList();
虽然Concrete
实现了IInter
,但List<Concrete>
不是List<IInter>
。
你可以使用:
List<IInter> t = ConcreteList.Cast<IInter>().ToList();
协方差和逆变性FAQ
因为您不能将List<ConcreteA>
分配给List<IInter>
,否则您可以这样做:
concreteAList = newList<ConcreteA>();
List<Inter> interList = concreteAList as List<Inter>; // seems harmless
interList.Add(new ConcreteB()); // not allowable
你可以做:
var t = new List<List<IInter>>()
{
new List<IInter>(){/* ... fill with ConcreteAs ... */},
new List<IInter>(){/* ... fill with ConcreteBs ... */},
// ...
new List<IInter>(){/* ... fill with ConcreteXs ... */},
};
但我不知道这是否达到了你的目的。
这被称为协方差, c#在泛型接口而不是泛型类上支持协方差(和逆变)。这是以下工作,但你的例子没有:
IEnumerable<IInter> e = new List<Concrete>();
ICollection<IInter> c = new List<Concrete>();
协方差也支持数组:
IInter[] a = new Concrete[3];
为需要从SingletonFactory<T>
访问的方法创建一个协变接口。这将确保您的类型T是输出类型安全的。
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 }
};
一种方法是:
IEnumerable<IInter> t = new List<Concrete>();
另一个原因是:
List<IInter> t = new List<Concrete>().ConvertAll(x => (IInter) x);
编辑,添加更好的示例来显示它工作(测试通过):
[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));
}