C#开启类型


C# switch on type

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

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

C不支持打开对象类型。模拟这个的最佳模式是什么:

1
2
3
4
switch (typeof(MyObj))
    case Type1:
    case Type2:
    case Type3:

谢谢!


我通常使用类型和委托的字典。

1
2
3
4
5
6
7
var @switch = new Dictionary<Type, Action> {
    { typeof(Type1), () => ... },
    { typeof(Type2), () => ... },
    { typeof(Type3), () => ... },
};

@switch[typeof(MyType)]();

这有点不太灵活,因为你不能掉进箱子,继续等等,但我很少这样做。


对于这个问题,有一个简单的答案,在类型C的开关盒上,它使用类型字典来查找lambda函数。

这是它的使用方法

1
2
3
4
5
6
7
8
9
    var ts = new TypeSwitch()
        .Case((int x) => Console.WriteLine("int"))
        .Case((bool x) => Console.WriteLine("bool"))
        .Case((string x) => Console.WriteLine("string"));

    ts.Switch(42);    
    ts.Switch(false);  
    ts.Switch("hello");
}

在开关/模式匹配思想下,对于模式匹配(类型和运行时检查条件)也有一个通用的解决方案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  var getRentPrice = new PatternMatcher<int>()
        .Case<MotorCycle>(bike => 100 + bike.Cylinders * 10)
        .Case<Bicycle>(30)
        .Case<Car>(car => car.EngineType == EngineType.Diesel, car => 220 + car.Doors * 20)
        .Case<Car>(car => car.EngineType == EngineType.Gasoline, car => 200 + car.Doors * 20)
        .Default(0);

    var vehicles = new object[] {
        new Car { EngineType = EngineType.Diesel, Doors = 2 },
        new Car { EngineType = EngineType.Diesel, Doors = 4 },
        new Car { EngineType = EngineType.Gasoline, Doors = 3 },
        new Car { EngineType = EngineType.Gasoline, Doors = 5 },
        new Bicycle(),
        new MotorCycle { Cylinders = 2 },
        new MotorCycle { Cylinders = 3 },
    };

    foreach (var v in vehicles)
    {
        Console.WriteLine("Vehicle of type {0} costs {1} to rent", v.GetType(), getRentPrice.Match(v));
    }


更新:这在C 7.0中得到了修正,模式匹配

1
2
3
4
switch (MyObj)
    case Type1 t1:
    case Type2 t2:
    case Type3 t3:

老回答:

这是C的比赛中的一个洞,还没有银弹。

你应该用谷歌搜索"访客模式",但这对你来说可能有点沉重,但仍然是你应该知道的。

下面是使用linq对这个问题的另一种看法:http://community.bartdesmet.net/blogs/bart/archive/2008/03/30/a-functional-c-type-switch.aspx

否则,沿着这条线的东西会有帮助

1
2
3
4
5
6
7
8
// nasty..
switch(MyObj.GetType.ToString()){
  case"Type1": etc
}

// clumsy...
if myObj  is Type1 then
if myObj is Type2 then

等。


我做过一次,希望能有所帮助。

1
2
3
4
5
6
7
8
string fullName = typeof(MyObj).FullName;

switch (fullName)
{
    case"fullName1":
    case"fullName2":
    case"fullName3":
}


我很少使用这种形式的switch-case。即使这样,我也找到了另一种方法去做我想做的事情。如果你发现这是实现你所需要的唯一方法,我会推荐@mark h的解决方案。

如果这是一种工厂创建决策过程,有更好的方法来实现。否则,我真的不明白你为什么要在一个类型上使用开关。

下面是一个关于Mark解决方案的小例子。我认为这是一种很好的工作方式:

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
26
27
28
29
30
31
32
33
Dictionary<Type, Action> typeTests;

public ClassCtor()
{
    typeTests = new Dictionary<Type, Action> ();

    typeTests[typeof(int)] = () => DoIntegerStuff();
    typeTests[typeof(string)] = () => DoStringStuff();
    typeTests[typeof(bool)] = () => DoBooleanStuff();
}

private void DoBooleanStuff()
{
   //do stuff
}

private void DoStringStuff()
{
    //do stuff
}

private void DoIntegerStuff()
{
    //do stuff
}

public Action CheckTypeAction(Type TypeToTest)
{
    if (typeTests.Keys.Contains(TypeToTest))
        return typeTests[TypeToTest];

    return null; // or some other Action delegate
}