【问题标题】:C# switch on type [duplicate]C#打开类型[重复]
【发布时间】:2011-05-27 13:56:14
【问题描述】:

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

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

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

【问题讨论】:

标签: c# switch-statement typeof


【解决方案1】:

gjvdkamp's answer;此功能现在存在于 C# 中


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

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

@switch[typeof(MyType)]();

它有点不灵活,因为你不能通过案例,继续等等。但无论如何我很少这样做。

【讨论】:

  • 您可能应该检查该类型是否在字典中。可以像这样相当简单if(@switch.ContainsKey(typeof(MyType))) @switch[typeof(MyType)]();
  • 这应该是一个非常有效/高性能的解决方案。请注意,这不适用于子类。
  • @YevgeniGrinberg 我还没有测试过这个,但我确信 typeof(object) != typeof(MyType) 即使 MyType 是对象的子类。
  • 如果您想要一个适用于子类型的解决方案,那么在某些时候必须使用IsAssignableFrom 进行比较。 This answer supports sub-types 但它的用法有点冗长
  • 我宁愿使用Action action; if(@switch.TryGetValue(typeof(Type1), out action) action(); 而不是搜索两次..(包含和索引器)
【解决方案2】:

更新: 这在 C# 7.0 中通过pattern matching 得到了修复

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

等等

【讨论】:

  • 功能 c 型开关的问题在于它没有获得实际 switch-case 语法所获得的预编译速度。这可能会诱骗程序员过度使用这个 look-alike 类,以为它具有相同的优势。这看起来像是更昂贵的if-then-with-lambdas 的迷人包装。
  • 抱歉,ToString 似乎是一个糟糕的计划 - 因为使用 Visual Studio 重命名类型会破坏这一点。为什么不typeOf(Type1)
  • 这没有回答问题。问题是关于打开类型,而不是关于打开对象的类型。
  • 该代码示例从字面上切换了 MyObj 的类型。
  • 您能否更新此内容以显示如何打开实际的 Type 实例?有类似switch (typeInstance) { case int: { ... } }
【解决方案3】:

a simple answer to this question 使用类型字典查找 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");

在模式匹配方面还有a generalized solution to this problem(类型和运行时检查条件):

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

【讨论】:

    【解决方案4】:

    我曾经做过一次解决方法,希望对您有所帮助。

    string fullName = typeof(MyObj).FullName;
    
    switch (fullName)
    {
        case "fullName1":
        case "fullName2":
        case "fullName3":
    }
    

    【讨论】:

    • 如果您重命名/移动任何类,这种方法很脆弱。
    • 稍微重构一下,你就完蛋了。
    • 这在 C# 6.0 中使用 nameof 时不那么脆弱:case nameof()
    • 您将使用 nameof() 而不是 nameof()。例如,在上面的示例中,nameof(MyObj)。但是我错了,因为这是打开全名,而 nameof 只会给你类名。
    • 为什么不使用 case case nameof(MyClass): break; 以便它更可重构
    【解决方案5】:

    我很少使用这种形式的switch-case。即使这样,我也找到了另一种方法来做我想做的事。如果您发现这是完成您需要的唯一方法,我会推荐@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
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-04
      • 2021-06-24
      • 1970-01-01
      • 2011-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多