23

我目前正在向此代码添加一些新的扩展类:

foreach (BaseType b in CollectionOfExtendedTypes) {
  if (b is ExtendedType1) {
    ((ExtendedType1) b).foo = this;

  }
  else if (b is ExtendedType2) {
    ((ExtenedType2) b).foo = this;

  } 
  else {
    b.foo = this;

  }
}

并且很好奇是否有办法is在 switch 语句中使用关键字功能?

4

11 回答 11

36

最新版本的 C# (7) 现在包含此功能

类型模式

类型模式可以实现简洁的类型评估和转换。当与 switch 语句一起使用来执行模式匹配时,它会测试表达式是否可以转换为指定的类型,如果可以,则将其转换为该类型的变量。它的语法是:

   case type varname 
于 2017-11-30T14:06:29.567 回答
15

这看起来确实像是一个好的多态实现的情况。如果在派生类中重写适当的方法,则可能根本不需要循环中的检查。

于 2008-10-21T22:06:15.290 回答
5

没有。看

C# switch 语句限制 - 为什么?

于 2008-10-21T21:54:46.687 回答
4

在 C# 中,不能将“is”关键字用作 switch 语句的一部分。switch 中的所有 case 标签都必须计算为常量表达式。"is" 不能转换为常量表达式。

不过,在切换类型时,我肯定会感到痛苦。因为您概述的解决方案确实有效,但它是 x do y 和 a do b 的一种复杂说法。像下面这样写会更自然


TypeSwitch.Do(
    sender,
    TypeSwitch.Case<Button>(() => textBox1.Text = "Hit a Button"),
    TypeSwitch.Case<CheckBox>(x => textBox1.Text = "Checkbox is " + x.Checked),
    TypeSwitch.Default(() => textBox1.Text = "Not sure what is hovered over"));

这是我写的关于如何实现此功能的博客文章。

http://blogs.msdn.com/jaredpar/archive/2008/05/16/switching-on-types.aspx

于 2008-10-21T21:57:03.920 回答
2

虽然不可能使用 switch 语句来检查类型,但将问题减少到更易于管理的代码库并非不可能。

根据具体情况和要求,我会考虑。

  • 使用 aIDictionary<Type, T>将结果存储在字典中。T 本身可以是您可以调用的委托。如果您不需要担心继承,这将起作用 - 满足继承需要更多的工作。

  • 在 switch 语句中使用类的类型名称(字符串)。这使用switch (b.GetType().Name)并且没有用于深度继承结构的选项。

于 2008-10-21T22:04:58.240 回答
2

正如MikeT的回答中提到的,您可以使用需要 C# 7的模式数学。

这是您的代码的示例:

foreach (BaseType b in CollectionOfExtendedTypes) {
  switch (b) {
    case ExtendedType1 et1:
        // Do stuff with et1.
        et1.DoStuff();
        break;
    case ExtendedType2 et2:
        // Do stuff with et2.
        et2.DoOtherStuff();
        break;
    default:
        // Do something else...
        break;
  }
}
于 2018-04-06T08:11:25.733 回答
1

您可以添加一个由每个具体子类实现的方法getType()BaseType返回一个唯一的整数 ID(可能是一个枚举)并打开它,是吗?

于 2008-10-21T21:59:29.047 回答
1

并非如此,开关将变量(字符串或 int(或枚举))与常量表达式匹配为 switch 语句。

http://msdn.microsoft.com/en-us/library/06tc147t(VS.71).aspx

于 2008-10-21T22:01:10.323 回答
0

根据我的经验,类型案例和面向对象的代码似乎并没有很好地结合在一起。在这种情况下我更喜欢的方法是双重调度模式。简而言之:

  • 使用空虚方法 Process(ExtendedTypeN arg) 为您将分派的每个扩展类型 创建一个侦听器类型。
  • 将虚拟方法Dispatch(Listener listener) 添加到将侦听器作为参数的基本类型。它的实现将是调用 listener.Process((Base) this)。
  • 覆盖每个扩展类型中的Dispatch方法,以调用侦听器类型中适当的 Process
  • 通过为您感兴趣的每个子 类型覆盖适当的 Process 方法来扩展侦听器类型。

参数改组舞蹈通过将其折叠到对 Dispatch 的调用中来消除缩小范围——接收者知道它的确切类型,并通过回调其类型的 Process 的确切重载来传达它。这也是 .NET Compact Framework 等实现中的一大性能优势,在这些实现中,缩小转换非常慢,但虚拟调度非常快。

结果将是这样的:


public class Listener
{
    public virtual void Process(Base obj) { }
    public virtual void Process(Derived obj) { }
    public virtual void Process(OtherDerived obj) { }
}

public class Base
{
    public virtual void Dispatch(Listener l) { l.Process(this); }
}

public class Derived
{
    public override void Dispatch(Listener l) { l.Process(this); }
}

public class OtherDerived
{
    public override void Dispatch(Listener l) { l.Process(this); }
}

public class ExampleListener
{
    public override void Process(Derived obj)
    {
        Console.WriteLine("I got a Derived");
    }

    public override void Process(OtherDerived obj)
    {
        Console.WriteLine("I got an OtherDerived");
    }

    public void ProcessCollection(IEnumerable collection)
    {
        foreach (Base obj in collection) obj.Dispatch(this);
    }
}
于 2009-01-16T04:23:47.570 回答
-1

在 C# 中,我相信 switch 语句只适用于整数和字符串。

于 2008-10-21T21:53:56.767 回答
-1

switch除了编译器处理语句的方式之外,还有一件事要考虑,那就是is运算符的功能。两者之间有很大区别:

if (obj is Foo)

if (obj.GetType() == typeof(Foo))

尽管有名称,但is运算符会告诉您对象是否与给定类型兼容,而不是告诉您它是否属于给定类型。这会导致看起来像这样的不完全明显的错误(尽管这个非常明显):

if (obj is System.Object)
{
   //this will always execute
}
else if (obj is Foo)
{
   //this will never execute
}

这里的许多建议为您指明了使用对象类型的方向。如果您真正想要的是与每种类型关联的逻辑,那很好。但如果是这种情况,使用is操作员时请小心行走。

另外:虽然您不能修改这些基本类型,但这并不意味着您不能使用 Owen 的建议。您可以实现扩展方法:

public enum MyType { Foo, Bar, Baz };
public static class MyTypeExtension
{
   public static MyType GetMyType(this Foo o)
   {
      return MyType.Foo;
   }
   public static MyType GetMyType(this Bar o)
   {
      return MyType.Bar;
   }
   public static MyType GetMyType(this Baz o)
   {
      return MyType.Baz;
   }
}

然后你可以使用一个switch语句:

switch (myObject.GetType())
{
   case MyType.Foo:
     // etc.
于 2008-10-21T22:56:51.117 回答