在 c# 中的开关中使用“is”关键字

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/223643/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 18:51:02  来源:igfitidea点击:

using the 'is' keyword in a switch in c#

c#switch-statement

提问by sre

I'm currently adding some new extended classes to this code:

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

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;

  }
}

and was curious if there is a way to use the iskeyword functionality in a switch statement?

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

采纳答案by Austin Salonen

This really looks like a situation for a good polymorphic implementation. If you override the appropriate methods in the derived classes, you may not need the checks in the loop at all.

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

回答by Ray Li

In C#, I believe the switch statement only works with integers and strings.

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

回答by JaredPar

In C# it's not possible to use the "is" keyword as part of a switch statement. All case labels in a switch must evaluate to constant expressions. "is" is not convertible to a constant expression.

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

I definately feel the pain though when it comes to switching on types. Because really the solution you outlined works but it's a conveluted way of saying for x do y, and a do b. It would be much more natular to write it more like the following

不过,在切换类型时,我肯定会感到痛苦。因为您概述的解决方案确实有效,但它是 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"));

Here's a blog post I wrote on how to achieve this functionality.

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

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

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

回答by Owen

You could add a method getType()to BaseTypethat is implemented by each concrete subclass to return a unique integral ID (possibly an enum) and switch on that, yes?

你可以添加一个方法getType()BaseType由每个具体的子类实现对返回独特整体ID(可能是一个枚举)和开关,是吗?

回答by Fry

Not really, switches match a variable (string or int (or enum) ) with a constant expression as the switch statement.

不是真的,switch 匹配一个变量(string 或 int(或 enum))和一个常量表达式作为 switch 语句。

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

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

回答by Samuel Kim

While it is not possible to use switch statement for checking types, it is not impossible to reduce the problem to a more manageable codebase.

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

Depending on the specific situation and requirement I would consider.

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

  • Using a IDictionary<Type, T>to store the result in a dictionary. T could itself be a delegate that you can call on. This will work if you don't need to worry about inheritance - catering for inheritance will take a little more work.

  • Using the type name of the class (which is string) inside the switch statement. This uses switch (b.GetType().Name)and there is no option for deep inheritance structure.

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

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

回答by Robert Rossney

There's another thing to think about besides the way that the compiler handles switchstatements, and that's the functioning of the isoperator. There's a big difference between:

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

if (obj is Foo)

and

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

Despite the name, the isoperator tells you if an object is compatiblewith a given type, not if it isof the given type. This leads to not-entirely-obvious bugs (though this one's pretty obvious) that look like:

尽管名称如此,is运算符会告诉您对象是否与给定类型兼容,而不是它是否属于给定类型。这会导致不完全明显的错误(尽管这个很明显),如下所示:

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

Many of the suggestions here point you in the direction of using the object's type. That's fine if what you really want is logic associated with each type. But if that's the case, walk carefully when using the isoperator.

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

Also: though you can't modify these base types, that doesn't mean that you can't use Owen's suggestion. You could implement extension methods:

另外:虽然您不能修改这些基本类型,但这并不意味着您不能使用 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;
   }
}

Then you canuse a switchstatement:

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

switch (myObject.GetType())
{
   case MyType.Foo:
     // etc.

回答by Jeffrey Hantin

Type-cases and object oriented code don't seem to get on that well together in my experience. The approach I prefer in this situation is the double dispatch pattern. In short:

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

  • Create a listener typewith an empty virtual method Process(ExtendedTypeN arg) for each extended type you will be dispatching over.
  • Add a virtual methodDispatch(Listener listener) to the base type that takes a listener as argument. Its implementation will be to call listener.Process((Base) this).
  • Overridethe Dispatch method in each extended type to call the appropriate overloadof Process in the listener type.
  • Extend the listener typeby overriding the appropriate Process method for each subtype you are interested in.
  • 为您将要调度的每个扩展类型创建一个带有空虚拟方法 Process(ExtendedTypeN arg)的侦听器类型
  • 将虚拟方法Dispatch(Listener listener) 添加到将侦听器作为参数的基本类型。它的实现将是调用 listener.Process((Base) this)。
  • 在每个扩展类型的调度方法来调用适当的负荷工艺在听者类型。
  • 通过为您感兴趣的每个子类型覆盖适当的 Process 方法来扩展侦听器类型

The argument shuffling dance eliminates the narrowing cast by folding it into the call to Dispatch -- the receiver knows its exact type, and communicates it by calling back the exact overload of Process for its type. This is also a big performance win in implementations such as .NET Compact Framework, in which narrowing casts are extremely slow but virtual dispatch is fast.

参数 shuffling dance 通过将其折叠到对 Dispatch 的调用中来消除缩小转换——接收器知道它的确切类型,并通过回调它的类型的 Process 的确切重载来传达它。这在 .NET Compact Framework 等实现中也是一个巨大的性能优势,在这些实现中,缩小强制转换非常慢,但虚拟分派很快。

The result will be something like this:

结果将是这样的:


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

回答by MikeT

The latest version of C# (7) now includes this functionality

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

Type pattern

类型模式

The type pattern enables concise type evaluation and conversion. When used with the switch statement to perform pattern matching, it tests whether an expression can be converted to a specified type and, if it can be, casts it to a variable of that type. Its syntax is:

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

   case type varname