可能的重复: c# -有没有比“打开类型”更好的选择?

c#不支持切换对象的类型。 模拟这种情况的最佳模式是什么:

switch (typeof(MyObj))
    case Type1:
    case Type2:
    case Type3:

当前回答

这个问题有一个简单的答案,使用类型字典来查找lambda函数。下面是它的用法:

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

就模式匹配(包括类型和运行时检查条件)而言,还有一个通用的解决方案:

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中通过模式匹配得到了解决

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

否则,沿着这些路线的东西可能会有所帮助

// nasty..
switch(MyObj.GetType().ToString()){
  case "Type1": etc
}

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

etc.

我曾经做过一次,希望有帮助。

string fullName = typeof(MyObj).FullName;

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

看到另一个答案;这个特性现在已经存在于c#中了


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

var @switch = new Dictionary<Type, Action> {
    { typeof(Type1), () => ... },
    { typeof(Type2), () => ... },
    { typeof(Type3), () => ... },
};

@switch[typeof(MyType)]();

它有点不太灵活,因为你不能摔倒,继续等等。但我也很少这样做。

我很少使用这种形式的开关箱。即便如此,我还是找到了另一种方法来做我想做的事。如果你发现这是完成你需要的唯一方法,我会推荐@Mark H的解决方案。

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

下面是一个扩展Mark解决方案的小例子。我认为这是处理类型的好方法:

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
}

这个问题有一个简单的答案,使用类型字典来查找lambda函数。下面是它的用法:

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

就模式匹配(包括类型和运行时检查条件)而言,还有一个通用的解决方案:

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