使用';是';关键字在c#中的开关中

本文关键字:开关 关键字 使用 | 更新日期: 2023-09-27 17:48:49

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

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

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

使用';是';关键字在c#中的开关中

C#(7)的最新版本现在包括

类型模式

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

   case type varname 

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

否。参见

C#开关语句的限制-为什么?

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

不过,当谈到切换类型时,我确实感到痛苦。因为你概述的解决方案确实有效,但这是一种简单的x做y和a做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

正如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;
  }
}

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

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

  • 使用IDictionary<Type, T>将结果存储在字典中。T本身可以是一个您可以调用的委托。如果您不需要担心继承,这将起作用——为继承提供服务将需要更多的工作。

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

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

实际上,开关将变量(字符串或int(或enum))与常量表达式匹配作为开关语句。

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

根据我的经验,类型案例和面向对象代码似乎相处得不太好。在这种情况下,我更喜欢的方法是双重调度模式。简而言之:

  • 为要调度的每个扩展类型创建一个侦听器类型,并使用空的虚拟方法Process(ExtendedTypeN arg)。
  • 将一个虚拟方法Dispatch(侦听器侦听器)添加到将侦听器作为参数的基类型中。它的实现将是调用监听器。处理(基于)此)。
  • Override每个扩展类型中的Dispatch方法,以调用侦听器类型中Process的适当的Overload
  • 通过为您感兴趣的每个子类型重写适当的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);
    }
}

您可以在C#8.0中使用切换表达式和模式匹配。

这是Microsoft提供的文档:https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/patterns

托马斯·克劳迪斯的这篇博客文章展示了它是如何做到的。https://www.thomasclaudiushuber.com/2021/02/25/c-9-0-pattern-matching-in-switch-expressions/

下面是url中的示例:

object obj = ...
string favoriteTask = obj switch
{
  Developer dev when dev.YearOfBirth == 1980 => $"{dev.FirstName} listens to metal",
  Developer dev => $"{dev.FirstName} writes code",
  Manager _ => "Create meetings",
  _ => "Do what objects do",
};

除了编译器处理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运算符时要小心。

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

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.

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