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语句检查类型,但也不可能将问题简化为更易于管理的代码库 根据具体情况和要求,我会考虑。
- 使用
将结果存储在字典中。T本身可以是您可以调用的代理。如果您不需要担心继承问题,那么这将起作用——为继承服务将需要更多的工作IDictionary
- 在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;
}
}