C# 使用';是';c语言中开关中的关键字#

C# 使用';是';c语言中开关中的关键字#,c#,switch-statement,C#,Switch Statement,我目前正在向该代码中添加一些新的扩展类: 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; } }

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

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#中,我相信switch语句只适用于整数和字符串。

没有。看

在C#中,不能将“is”关键字用作switch语句的一部分。开关中的所有大小写标签都必须计算为常量表达式。“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"));

打字开关(
发件人,
TypeSwitch.Case(()=>textBox1.Text=“点击按钮”),
TypeSwitch.Case(x=>textBox1.Text=“复选框为”+x.Checked),
TypeSwitch.Default(()=>textBox1.Text=“不确定悬停的内容”);
下面是我写的一篇关于如何实现此功能的博客文章


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

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


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

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

  • 使用
    IDictionary
    将结果存储在字典中。T本身可以是您可以调用的代理。如果您不需要担心继承问题,那么这将起作用——为继承服务将需要更多的工作

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


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

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

if (obj is Foo)

不管名称如何,
is
操作符都会告诉您对象是否与给定类型兼容,而不是是否与给定类型兼容。这会导致不完全明显的bug(尽管这一个很明显),看起来像:

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 (myObject.GetType())
{
   case MyType.Foo:
     // etc.

根据我的经验,类型用例和面向对象代码似乎不太合拍。在这种情况下,我更喜欢的方法是。简言之:

  • 为要分派的每个扩展类型创建一个具有空虚拟方法进程(ExtendedTypeN arg)的侦听器类型。
  • 将虚拟方法分派(侦听器侦听器)添加到以侦听器作为参数的基类型。它的实现将是调用listener.Process((Base)this)。
  • 重写每个扩展类型中的Dispatch方法,以调用侦听器类型中相应的进程重载。
  • 通过覆盖您感兴趣的每个子类型的相应流程方法来扩展侦听器类型。
参数洗牌舞蹈通过将其折叠到分派调用中消除了收窄转换——接收者知道其确切类型,并通过为其类型回调确切的进程重载来进行通信。在.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#(7)现在包含了此功能

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

   case type varname 
如from中所述,您可以使用需要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;
  }
}

这对我来说似乎也很自然,但它们不是我可以玩的基本类。thx Though除非我弄错了,否则您应该能够更改类设计,以便在其他情况下,为了支持简单的“b.foo=this;”而不需要构造,因为它不适用于
foo obj=new Baz()
然后
obj.GetMyType()
返回
Foo
而不是
Baz
。请举个例子好吗?@demoave当然有一些时候你不能这样做,所以它与常量一起工作,所以任何可以用作常量字符串、int、double、float、bool等的东西都很棒!感谢您将此添加到旧问题中,现在应将其标记为答案。
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;
  }
}