在 C# 8 中 System.Type 上切换表达式
Switch expression on System.Type in C# 8
我很好奇是否还有其他方法可以在 C# 8 中用新的 switch 表达式编写类似的东西?
public static object Convert(string str, Type type) =>
type switch
{
_ when type == typeof(string) => str,
_ when type == typeof(string[]) => str.Split(new[] { ',', ';' }),
_ => TypeDescriptor.GetConverter(type).ConvertFromString(str)
};
因为 _ when type == typeof(string)
看起来有点奇怪,尤其是当我们有 type pattern 和其他非常方便的工具时。
正如其他人所暗示的,您实际上需要有一个类型的 实例 才能使用新的类型匹配功能,而不是代表 System.Type
。如果你想直接在类型上匹配,你这样做的方式似乎是目前唯一可行的方式。
话虽这么说,但在这种情况下,我认为标准 switch
语句可能更具可读性:
switch (type)
{
case Type _ when type == typeof(string):
return str;
case Type _ when type == typeof(string[]):
return str.Split(',', ';');
default:
return TypeDescriptor.GetConverter(type).ConvertFromString(str);
}
如果您真的想要保留 switch 表达式,您可以通过匹配类型名称来解决这个问题,尽管正如下面评论者指出的那样,这个选项特别有用脆弱,不适用于某些类型(例如 DateTime?
或 Nullable<DateTime>
):
public static object Convert(string str, Type type) =>
type.Name switch
{
nameof(string) => str,
nameof(string[]) => str.Split(new[] { ',', ';' }),
_ => TypeDescriptor.GetConverter(type).ConvertFromString(str)
};
如果您要使用泛型并使用最新的 c# 版本,您可以这样做:
public partial class DateMultiSelect<TDate> where TDate: struct
{
protected override void OnParametersSet()
{
if(default(TDate) switch
{
DateOnly => true,
DateTime => true,
DateTimeOffset => true,
_ => false
})
throw new ArgumentException($"TDate must be a date type, but is {typeof(TDate).Name}");
base.OnParametersSet();
}
}
根据你的例子,这应该是这样的:
(可以编译,但是运行时没测试)
public static T? Convert<T>(string? str) =>
default(T) switch
{
string => (T?)(dynamic?)str,
string[] => (T?)(dynamic?)str?.Split(new[] { ',', ';' }),
_ => (T?)TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(str)
};
也可以使用对象来代替动态。
我很好奇是否还有其他方法可以在 C# 8 中用新的 switch 表达式编写类似的东西?
public static object Convert(string str, Type type) =>
type switch
{
_ when type == typeof(string) => str,
_ when type == typeof(string[]) => str.Split(new[] { ',', ';' }),
_ => TypeDescriptor.GetConverter(type).ConvertFromString(str)
};
因为 _ when type == typeof(string)
看起来有点奇怪,尤其是当我们有 type pattern 和其他非常方便的工具时。
正如其他人所暗示的,您实际上需要有一个类型的 实例 才能使用新的类型匹配功能,而不是代表 System.Type
。如果你想直接在类型上匹配,你这样做的方式似乎是目前唯一可行的方式。
话虽这么说,但在这种情况下,我认为标准 switch
语句可能更具可读性:
switch (type)
{
case Type _ when type == typeof(string):
return str;
case Type _ when type == typeof(string[]):
return str.Split(',', ';');
default:
return TypeDescriptor.GetConverter(type).ConvertFromString(str);
}
如果您真的想要保留 switch 表达式,您可以通过匹配类型名称来解决这个问题,尽管正如下面评论者指出的那样,这个选项特别有用脆弱,不适用于某些类型(例如 DateTime?
或 Nullable<DateTime>
):
public static object Convert(string str, Type type) =>
type.Name switch
{
nameof(string) => str,
nameof(string[]) => str.Split(new[] { ',', ';' }),
_ => TypeDescriptor.GetConverter(type).ConvertFromString(str)
};
如果您要使用泛型并使用最新的 c# 版本,您可以这样做:
public partial class DateMultiSelect<TDate> where TDate: struct
{
protected override void OnParametersSet()
{
if(default(TDate) switch
{
DateOnly => true,
DateTime => true,
DateTimeOffset => true,
_ => false
})
throw new ArgumentException($"TDate must be a date type, but is {typeof(TDate).Name}");
base.OnParametersSet();
}
}
根据你的例子,这应该是这样的: (可以编译,但是运行时没测试)
public static T? Convert<T>(string? str) =>
default(T) switch
{
string => (T?)(dynamic?)str,
string[] => (T?)(dynamic?)str?.Split(new[] { ',', ';' }),
_ => (T?)TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(str)
};
也可以使用对象来代替动态。