【问题标题】:How to use switch-case on a Type? [duplicate]如何在 Type 上使用 switch-case? [复制]
【发布时间】:2011-09-25 00:16:43
【问题描述】:

可能重复:
Is there a better alternative than this to 'switch on type'?

我需要遍历我的类的所有属性并检查它的 int 类型是否我需要做某事,如果它的字符串 .. 则做某事。我需要它使用开关盒。在这里,我以下列方式使用 switch,但它要求一些常数。看下面的代码:

 public static bool ValidateProperties(object o)
{
    if(o !=null)
    {
        var sourceType = o.GetType();
        var properties = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Static);
        foreach (var property in properties)
        {
            var type = property.GetType();
            switch (type)
            {
                *case typeof(int):* getting error here
                    // d
            }
        }
    }
}

我也想知道,我应该使用什么检查,typeof(int) 还是 typeof(Int32)?

【问题讨论】:

标签: c#


【解决方案1】:

您不能使用开关块来测试Type 类型的值。编译你的代码应该会给你一个错误,比如:

switch 表达式或 case 标签必须是 bool、char、string、 整数、枚举或对应的可空类型

您需要改用if-else 语句。

另外:typeof(int)typeof(Int32) 是等价的。 int 是关键字,Int32 是类型名称。

更新

如果您希望大多数类型是固有的,您可以通过使用带有Type.GetTypeCode(...) 的开关块来提高性能。

例如:

switch (Type.GetTypeCode(type))
{
    case TypeCode.Int32:
        // It's an int
        break;

    case TypeCode.String:
        // It's a string
        break;

    // Other type code cases here...

    default:
        // Fallback to using if-else statements...
        if (type == typeof(MyCoolType))
        {
            // ...
        }
        else if (type == typeof(MyOtherType))
        {
            // ...
        } // etc...
}

【讨论】:

    【解决方案2】:

    实现此目的的一种好的且可扩展的方法是根据您要对该类型的值执行的操作,制作一个包含适当类型的类型和委托的字典。

    例如:

    var typeProcessorMap = new Dictionary<Type, Delegate>
    {
        { typeof(int), new Action<int>(i => { /* do something with i */ }) },
        { typeof(string), new Action<string>(s => { /* do something with s */ }) },
    };
    

    然后:

    void ValidateProperties(object o)
    {
        var t = o.GetType();
        typeProcessorMap[t].DynamicInvoke(o); // invoke appropriate delegate
    }
    

    此解决方案是可扩展的,即使在运行时也可配置,只要您保持 typeProcessorMap 中委托值的键和类型正确匹配也是类型安全的。

    See it in action.

    【讨论】:

    • 这是一个不错的解决方案,请记住 DynamicInvoke 在性能关键部分可能会有点慢。
    • @KirkWoll:让所有代表Action&lt;object&gt; 并在代表主体内转换参数会更快吗?我不确定DynamicInvoke 在幕后究竟做了什么。
    • 我也不确定DynamicInvoke 在幕后究竟做了什么。 :) 但是我在下面发布了一个“答案”来说明性能差异。
    • 显然已经/得到了 Skeet 的祝福in 2008。但是,ideone 链接对我不起作用(OS X 和 Safari)。
    【解决方案3】:

    通常,最简单的解决方案是打开类型名称:

    switch (type.Name)
    {
        case "Int32":
        ...
    }
    

    【讨论】:

    • IMO,牺牲类型安全是不值得的。毕竟,if/else 链几乎同样简洁,并且具有在编译时捕获拼写错误(更重要的是——未来的重构)的优点。
    • 你们听说过单元测试吗?无论如何,我有时确实会使用 Jon 的方法,但它通常是矫枉过正的。
    • @Diego,单元测试不是类型安全的替代品。
    【解决方案4】:

    这个“答案”是对乔恩答案的阐述。 (标记 CW)

    作为记录,DynamicInvoke 有点慢。为了说明这一点,请考虑以下程序:

    void Main()
    {
        Func<int, string> myFunc = i => i.ToString();
        myFunc.DynamicInvoke(1);   // Invoke once so initial run costs are not considered
        myFunc(1);
    
        Stopwatch stopwatch = new Stopwatch();
    
        stopwatch.Start();
        for (int i = 0; i < 1000000; i++)
            myFunc.DynamicInvoke(1);
        stopwatch.Stop();
    
        var elapsed = stopwatch.Elapsed;
    
        stopwatch.Restart();
        for (int i = 0; i < 1000000; i++)
            myFunc(1);
        stopwatch.Stop();
    
        var elapsed2 = stopwatch.Elapsed;
    
        Console.WriteLine("DynamicInvoke: " + elapsed);
        Console.WriteLine("Direct Invocation: " + elapsed2);
    }
    

    打印出来:

    动态调用:00:00:03.1959900
    直接调用:00:00:00.0735220

    这意味着DynamicInvoke(在这个简单的例子中)比直接调用慢 42 倍。

    【讨论】:

      猜你喜欢
      • 2017-07-21
      • 1970-01-01
      • 2019-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-25
      • 1970-01-01
      相关资源
      最近更新 更多