使用';是';关键字在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#(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语句只适用于整数和字符串。