我的上下文是,我正在构建一个简单的工厂方法,用于创建给定基类型的派生类型的实例。 工厂方法只接受类型参数,即没有任何参数。 这显然可以通过if
- else if
结构来实现:
public Vehicle Create<T>()
{
if (typeof(T) == typeof(Car))
return new Car(); // just an example; could be more complex logic.
else if (typeof(T) == typeof(Truck))
return new Truck(); // just an example; could be more complex logic.
else
throw new ArgumentException(
$"The type {typeof(T).Name} is not known by this method.");
}
现在众所周知,如何在 C# 中使用模式匹配(从 C# 7.0 开始(根据变量的类型进行分支,但这不适用于类型参数:
switch (T) { ... } // error: "'T' is a type, which is not valid in the given context"
或。。。
switch (typeof(T))
{
case Car c: ...
// err: "An expression of type 'Type' cannot be handled by a pattern of type 'Car'"
}
所以我想知道是否可以使用switch
来达到相同的结果?
研究:我很惊讶以前没有问过这个问题,但我找不到它。 我发现这篇文章有一个名称和一些非常接近的答案,但它正在处理具有类型T
参数的(数字(值类型和方法 - 泛型类型参数。 同样,这篇文章也使用了一个参数。
我知道你的问题特别问到使用 switch 语句,但另一种选择是创建一个以类型为键的工厂字典。
您应该注意,此时,您正在执行类似于依赖项注入的操作。 您请求的是 X 类型的车辆,如果 Create 方法没有创建类型 X 的车辆所需的信息,则冒着运行时错误的风险。
public class Car : Vehicle { }
public class Truck : Vehicle { }
public abstract class Vehicle
{
private static readonly IReadOnlyDictionary<Type, Func<Vehicle>> vehicleFactories = new Dictionary<Type, Func<Vehicle>>
{
{ typeof(Car), () => new Car() },
{ typeof(Truck), () => new Truck() }
};
public static Vehicle Create<T>() where T : Vehicle, new()
{
if (vehicleFactories.TryGetValue(typeof(T), out var factory))
{
return factory();
}
else
{
throw new ArgumentException(
$"The type {typeof(T).Name} is not known by this method.");
}
}
}
编辑:请注意,我不是在做任何关于这是好是坏的声明。 这完全是为了表明这是可能的。
这可以在 C# 7.0 或更高版本中使用具有模式匹配和 when
关键字的 switch
块来实现:
public Vehicle Create<T>() where T : Vehicle
{
switch (true)
{
case bool x when typeof(T) == typeof(Car): return new Car();
case bool x when typeof(T) == typeof(Truck): return new Truck();
default: throw new ArgumentException(
$"The type {typeof(T).Name} is not known by this method.");
}
}