关于c#:如何在Type上使用switch-case?


How to use switch-case on a Type?

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
Is there a better alternative than this to 'switch on type'?

我需要遍历类的所有属性,并检查它的int类型是否需要做一些事情,如果它的字符串..然后做点什么。我需要用开关盒。在这里,我使用开关的方式如下,但它要求一些常数。请参见下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 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)?


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

A switch expression or case label must be a bool, char, string,
integral, enum, or corresponding nullable type

您需要使用ifelse语句来代替。

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

更新

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

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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...
}


要做到这一点,一个好的、可扩展的方法是根据您想要对该类型的值执行的操作,创建一个类型和适当类型的委托的字典。

例如:

1
2
3
4
5
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 */ }) },
};

然后:

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

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

行动起来看看。


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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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);
}

打印输出:

DynamicInvoke: 00:00:03.1959900
Direct Invocation: 00:00:00.0735220

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


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

1
2
3
4
5
switch (type.Name)
{
    case"Int32":
    ...
}