是否有(优雅的)解决方案在方法中进一步约束泛型类型参数?

时间:2012-12-11 08:35:24

标签: c# generics type-constraints

我有一个通用基类Foo<T>,类Bar<U>Bat<T>从中派生出来。 U来自T。 Bat和Bar是类似的实现,仅在少数地方不同,其中必须以不同的方式处理类型U的值。

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不是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));

然而,这是非常糟糕的imo并且不能用于结构(U在这种情况下由于继承而无论如何都不能是结构,但我还有另一种情况,我想根据if {调用方法{1}}例如Tstruct

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

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

1 个答案:

答案 0 :(得分:0)

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

interface IFoo<in T> { ... }

有关C#中泛型和差异的更多信息,请查看this MSDN page

<强>更新

如果条件IFoo<U>IFoo<T> U : T(例如,IFoo的泛型类型是逆变),那么您可以在create方法中安全地进行投射:< / p>

return (IFoo<T>)((object)new Bar<U>());