2

我有一个通用基类Foo<T>,类Bar<U>Bat<T>派生自该基类。 U源自TUBat 和 Bar 是类似的实现,只是在几个必须以不同方式处理类型值的地方有所不同。

Foo中,我有一个工厂方法Create,它接受一个类型的参数T并且应该创建一个BarBat对象。它看起来大致是这样的:

public static IFoo<T> Create(T input) {
  if (input.TypeIdentifier == Types.Bar) {// exemplary type check
    // input is of or derives from `U`
    // return a Bar<U>
  } else 
    return new Bat(input);
}

// usage:
U myU = new ClassThatDerivesFromU();
T myT = new ClassThatDerivesFromT(CouldBe.Of(Type.U));
var myFoo1 = Create(myU); // of type IFoo<U>
var myFoo2 = Create(myT); // of type IFoo<T>

由于T不是 a U,因此我无法实例化Bar对象。

一种可能的解决方案是:

public static U To<T, U>(T input) where U : T {
  return input as U;
}

// to create Bar:
new Bar(To<T, U>(input));

然而,这完全是 hack imo,并且不能与结构一起使用(U在这种情况下,由于继承,无论如何都不能成为结构,但我还有另一种情况,我想根据 ifT是 astruct或 a来调用方法class)。

在 C++ 中,可以通过提供具有不同类型约束的方法的多个重载来解决(iirc)这样的场景Create,编译器将检查类型T并选择正确的方法(使用UT作为类型约束)。

我不知道 C# 中有类似的内置解决方案,但也许我可以使用一种优雅的解决方法?(反思是一个明显的答案,但不是一个选项)

4

1 回答 1

0

是的,使用接口时允许泛型变化。您可以将 IFoo 中的泛型类型参数声明为协变或逆变(取决于用法)。如果您希望使用更派生的类型,则该类型T必须是逆变的,并且 IFoo 可以声明如下:

interface IFoo<in T> { ... }

查看此 MSDN 页面,了解有关 C# 中的泛型和变异的更多信息。

更新

一旦你有了一个IFoo<U>is IFoo<T>if的条件U : T(例如 IFoo 的泛型是逆变的),那么你就可以在你的 create 方法中安全地进行转换:

return (IFoo<T>)((object)new Bar<U>());
于 2012-12-11T08:36:43.320 回答