我有一个通用基类Foo<T>
,类Bar<U>
和Bat<T>
从中派生出来。
U
来自T
。 Bat和Bar是类似的实现,仅在少数地方不同,其中必须以不同的方式处理类型U
的值。
在Foo
中,我有一个工厂方法Create
,它接受T
类型的参数,并且应该创建Bar
或Bat
对象。
看起来大致如下:
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}}例如T
或struct
。
在C ++中,这样的场景可以通过提供具有不同类型约束的class
方法的几个重载来解决(iirc),编译器将检查类型Create
并选择正确的方法(使用T
或U
作为类型约束。)
我不知道C#中有类似的内置解决方案,但也许我可以使用一个优雅的解决方法? (反思是一个明显的答案,但不是一种选择)
答案 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>());