简体   繁体   English

在 C# 8 中的 System.Type 上切换表达式

[英]Switch expression on System.Type in C# 8

I'm curious is any other way to write something like this with new switch expression 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)
    };

Because _ when type == typeof(string) looks kinda weird especially when we have type pattern and other very convenient instruments.因为_ when type == typeof(string)看起来有点奇怪,尤其是当我们有类型模式和其他非常方便的工具时。

As others have alluded to, you actually need to have an instance of a type available to use the new type-matching features, not the representative System.Type .正如其他人所暗示的那样,您实际上需要一个类型的实例来使用新的类型匹配功能,而不是代表性的System.Type If you want to match directly on the type, the way you're doing it seems to be the only viable way for the time being.如果您想直接在类型上进行匹配,那么您这样做的方式似乎是目前唯一可行的方式。

That being said, I would argue in this case that a standard switch statement might be more readable:话虽如此,在这种情况下,我认为标准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);
}

If you really want to keep the switch expression, you could potentially get around this by matching on type names instead, though as a commenter pointed out below, this option is particularly brittle and will not work with certain types (such as DateTime? or Nullable<DateTime> ):如果您真的想保留 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)
    };

If you would use generics and use the latest c# version you could do something like this:如果您使用 generics 并使用最新的 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();
    }
}

according to your example this would be something along those lines: (can be compiled, but didn't test it at runtime)根据您的示例,这将是类似的内容:(可以编译,但在运行时未对其进行测试)

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)
        };

instead of dynamic also object could be used.也可以使用 object 代替动态。

In a similar situation I ended up using a generic helper to make intent clearer.在类似的情况下,我最终使用了一个通用助手来使意图更清晰。 I did have <T> type available but not the C#9 default (T) switch { string[] =>...} syntax.我确实有<T>类型可用,但没有 C#9 default (T) switch { string[] =>...}语法。

This solution seems to be handling nullables like DateTime?这个解决方案似乎正在处理像DateTime? correctly.正确。

static object Convert(string str, Type type)
    => type switch {
        _ when Match<string>(type) => str,
        _ when Match<string[]>(type) => str.Split(new[] { ',', ';' }),
        _ => TypeDescriptor.GetConverter(type).ConvertFromString(str)
    };
static bool Match<T>(Type t) => typeof(T) == t;

For my <T> available case it became something like:对于我的<T>可用案例,它变成了这样:

static object Convert<T>(string str)
    => type switch
    {
        _ when Match<string, T>() => str,
        _ when Match<string[], T>() => str.Split(new[] { ',', ';' }),
        _ => TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(str)
    };
static bool Match<TA, TB>() => typeof(TA) == typeof(TB);

edit : One can shorten the syntax a bit with an extension method:编辑:可以使用扩展方法稍微缩短语法:

...
public static bool Is<T>(this System.Type type) => type == typeof(T);
...
static object Convert(string str, Type type)
    => type switch {
        _ when type.Is<string>() => str,
        _ when type.Is<string[]>() => str.Split(new[] { ',', ';' }),
        _ => TypeDescriptor.GetConverter(type).ConvertFromString(str)
    };

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM