2

我正在编写的通用方法遇到了一些麻烦。它具有以下签名;

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;

问题是如果我不强制转换新对象,我会得到一个最佳重载方法匹配无效参数错误。为 new Thing() 添加如上所示的 T 转换很好,但报告无法将类型 'ThingA' 转换为 'T'以用于其他新调用。Intellisense 表明 T 是一个事物,但我不明白为什么我不能将其他对象转换为事物,因为它们继承自它。

也许这不是做我想做的事情的正确方法。我在正确的轨道上吗?也许错过了一些细微的差别,或者我应该完全做其他事情吗?

4

4 回答 4

7

我不明白你想用那个代码做什么。

如果你想创建一个可以添加从 Thing 派生的任何类型的类的 Collection of Things,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。

于 2008-11-13T09:59:52.413 回答
3

主要是我认为,这个代码片段的设计很糟糕。如果添加“ThingD”类,则需要更改另一部分代码,以获得清晰的行为。你应该使用类似的东西:

public static ThingCollection<T> GetThings<T>(...) where T : Thing, new()
...
...
T item = new T();
item.Something = Whatever();

或者您可以实现“ICloneable”接口 int Thing 类。

于 2008-11-13T09:41:47.020 回答
3

该代码违反了 Liskov 替换原则,因为它在使用之前尝试测试 T 的类型。

为避免这种情况,您可以使用字典/策略组合或访问者模式。

如果 T 是 ThingB,则强制转换 (T)ThingA 无效,因此代码实际上是错误的。

于 2008-11-13T09:44:37.793 回答
2

如果他们使用通用接口(IThing),您应该能够转换为该接口。

于 2008-11-13T09:38:28.213 回答