我在编写一个通用方法时遇到了一些麻烦。它有以下签名;
public static ThingCollection<T> GetThings<T>(...) where T : Thing
有几个班级;从Thing继承的ThingA,ThingB和ThingC;我希望能够在方法中使用类似的代码。
var things = new ThingCollection<T>();
if (typeof(T) == typeof(Thing))
foreach (var item in someCollection)
things.Add((T)new Thing(...));
else if (typeof(T) == typeof(ThingA))
foreach (var item in someCollection)
things.Add((T)new ThingA(...));
else if (typeof(T) == typeof(ThingB))
foreach (var item in someCollection)
things.Add((T)new ThingB(...));
else if (typeof(T) == typeof(ThingC))
foreach (var item in someCollection)
things.Add((T)new ThingC(...));
else
throw new Exception("Cannot return things of type " + typeof(T).ToString());
return things;
问题是,如果我不转换新对象,我会得到最佳重载方法匹配包含无效参数错误。如上所示添加T强制转换适用于新的Thing(),但报告无法将其他新呼叫的类型'ThingA'转换为'T'。 Intellisense表明T是一个东西,但我不明白为什么我不能将其他对象强制转换为Thing,因为它们继承了它。
也许这不是正在做我想做的事情的正确方法。我是在正确的轨道上吗?也许缺少一些小细微差别,或者我应该完全做其他事情?
答案 0 :(得分:7)
我不知道你要用这个代码做什么。
如果你想创建一个可以添加从Thing派生的任何类型的类的集合,那么ThingCollection不应该有一个Typename:它应该是具体类型的集合。
例如,以这种方式实施A ThingCollection:
public class ThingCollection : List<Thing> {}
现在你可以做到
ThingCollection tc = new ThingCollection();
tc.Add(new ThingA());
tc.Add(new ThingB());
tc.Add(new ThingC());
当然假设ThingA,ThingB和ThingC继承自Thing。
或者您可能希望使用GetThings()过滤派生类型的事物,即您希望调用GetThings()返回ThingCollection。
答案 1 :(得分:3)
Primarly我认为,这段代码的设计很糟糕。如果添加“ThingD”类,则需要更改代码的另一部分,以获得清晰的行为。 你应该使用类似的东西:
public static ThingCollection<T> GetThings<T>(...) where T : Thing, new()
...
...
T item = new T();
item.Something = Whatever();
或者你可以实现“ICloneable”接口int Thing class。
答案 2 :(得分:3)
代码违反Liskov替换原则,因为它在使用之前尝试测试T的类型。
为避免这种情况,您可以使用字典/策略组合或访客模式。
如果T是ThingB,则转换(T)ThingA无效,因此代码实际上是错误的。
答案 3 :(得分:2)
如果他们使用通用界面(IThing),你应该能够使用它。