我目前正在为此代码添加一些新的扩展类:
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
关键字功能?
答案 0 :(得分:13)
这看起来像是一个良好的多态实现的情况。如果覆盖派生类中的相应方法,则可能根本不需要循环中的检查。
答案 1 :(得分:7)
最新版本的C#(7)现在包含此功能
类型模式可以实现简洁的类型评估和转换。当与switch语句一起使用以执行模式匹配时,它会测试表达式是否可以转换为指定的类型,如果可以,则将其转换为该类型的变量。它的语法是:
case type varname
答案 2 :(得分:5)
答案 3 :(得分:4)
在C#中,不能将“is”关键字用作switch语句的一部分。交换机中的所有案例标签必须评估为常量表达式。 “is”不能转换为常量表达式。
当谈到打开类型时,我肯定会感到痛苦。因为你所概述的解决方案确实有效,但它是x do 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
答案 4 :(得分:2)
虽然无法使用switch语句来检查类型,但是将问题简化为更易于管理的代码库并非不可能。
根据具体情况和要求,我会考虑。
使用IDictionary<Type, T>
将结果存储在字典中。 T本身可以成为你可以召集的代表。如果您不需要担心继承,这将有效 - 为继承而言需要更多的工作。
在switch语句中使用类的类型名称(字符串)。这使用switch (b.GetType().Name)
,并且没有深度继承结构的选项。
答案 5 :(得分:2)
正如answer中的MikeT所述,您可以使用需要C#7的pattern mathing。
以下是您的代码示例:
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;
}
}
答案 6 :(得分:1)
您可以向getType()
添加一个方法BaseType
,该方法由每个具体子类实现,以返回唯一的整数ID(可能是枚举)并启用它,是吗?
答案 7 :(得分:1)
实际上,switch将变量(string或int(或enum))与常量表达式作为switch语句匹配。
http://msdn.microsoft.com/en-us/library/06tc147t(VS.71).aspx
答案 8 :(得分:0)
在C#中,我认为switch语句只适用于整数和字符串。
答案 9 :(得分:0)
在我的经验中,类型案例和面向对象的代码似乎并没有很好地融合在一起。在这种情况下我更喜欢的方法是double dispatch pattern。简而言之:
参数shuffling dance通过将其折叠到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);
}
}
答案 10 :(得分:-1)
除了编译器处理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.