说,如果我想集中测试一些继承类的类型,并且需要良好的性能,我应该使用enum
存储所有可能的类型,并使用枚举相等来测试类型而不是使用{{ 1}}。
e.g。
is
或
switch (myObject.Type)
{
case myType.type1:
myObject as myInheritedObject1;
...
break;
case myType.type2:
myObject as myInheritedObject2;
...
break;
case myType.type3:
myObject as myInheritedObject3;
...
break;
...
}
答案 0 :(得分:10)
说,如果我想集中测试一些继承类的类型,并且需要良好的性能,我应该使用枚举存储所有可能的类型,并使用枚举相等来测试类型而不是使用
is
?
这种机制通常被称为“歧视型”,仅供参考。
答案是:这取决于您的性能要求。歧视类型有许多缺点:
switch
非常容易忘记一个案例,并在运行时可怕地死去,或者做一些疯狂的事情。它们的优势在于它们实际上比进行类型测试稍快。
因此,解决此问题的方法与解决任何其他性能问题的方法相同:
is
等标准惯用语的效果不符合您的要求,则评估是否对有区别的类型进行更改会导致程序符合您的要求。如果确实如此,那么考虑这样做的成本并做出相应的决定。如果没有那么你有一个更大的问题需要解决,所以先解决这个问题。在Roslyn团队中,我们以任何可能的方式都有极大限制性的性能要求,因此我们非常仔细地考虑了这个问题。我们决定采用在整个Roslyn中使用歧视类型的一般策略。这意味着我们必须非常小心关于我们设计交换机的方式,类型层次结构等等。我们还拥有一支专业的绩效团队,每天都会根据客户要求确认我们的绩效。
我们的要求与绝大多数业务线开发人员的性能要求完全不同;您不应该使用Roslyn代码作为确保良好性能的模型。相反,您应该使用我们的方法作为确保良好性能的模型:设置目标,经常测量,并且只有在实际上解决现有问题时才进行体系结构更改。 / p>
答案 1 :(得分:2)
理想情况下,您不必使用 - 而是使用多态来在派生类上执行所需的功能。
如果你必须确定我坚持as
/ is
的类型 - 这不太可能是你的性能瓶颈。
答案 2 :(得分:2)
这感觉就像糟糕的OO设计。如果您提供有关您要完成的内容的更多信息,我确信我们可以提供更多帮助(您可以使用模板模式,或使用接口约束的通用方法等),但这种类型的编码结构将很快成为维护的噩梦。此外,以这种方式使用enum
并不能真正解释继承层次结构。您可以在继承链中有一个is
基类型以及多个子类的类,但它只能有一个enum
值。
答案 3 :(得分:2)
如果你想密集测试一些继承类的类型,我会使用枚举,或者Eric Lippert称之为“Discriminated类型”。 Eric确定了这种技术的5个缺点,但我不同意大多数缺点。下面我将解决每一个问题:
他们使用更多内存。如果基类定义了子类中定义的抽象属性而不占用内存,则实例不需要占用更多内存。以下是一个例子:
abstract class MyBase
{
// Define each child class as a new MyType enum
public abstract MyType Type { get; }
}
class MyChild1 : MyBase
{
public override MyType Type
{
get { return MyType.Child1; }
}
}
编辑:添加其他示例。以上是不使用额外内存的示例。下面将使用额外的内存,因为“Discriminated type”被保存为基类上的字段,而不是在子类的代码中设置。如果将Type属性设置为abstract并在子类的代码中定义,则不使用额外的内存。
class MyBase
{
protected MyBase(MyType type) { this.type = type; }
MyType type;
public MyType Type { get { return type; } }
}
class MyChild1 : MyBase
{
public MyChild1() : base(MyType.Child1) { }
}
信息完全是多余的。这是事实,但是使用枚举和抽象属性会向开发人员调用子类是“被识别的类型”并且他们需要解决其他代码。
简而言之,如果确实需要这种类型的模式,并且您可以选择使用“识别类型”模式和“AS”/“IS”模式,我会选择前者,因为它更快,更容易阅读,更多自我记录。
答案 4 :(得分:1)
正如其他人所提到的那样,非常关注设计问题 - 你需要思考你的理由和“责任”......
对于一个非常“多样化”的继承层次结构(尤其是深层嵌套层次结构),
您可能会考虑访问者模式,这在这种情况下通常是一个很好的解决方案并且可以最大限度地减少麻烦,而且您不必检查,自动编码“重新路由”事物(即'设计'在这里是合适的:)。
但这只是一种问题的解决方案,有许多取决于你想要什么,需要。
希望它有所帮助(如果您需要任何示例,请告诉我。)
答案 5 :(得分:0)
我认为is
应该没有性能问题,但根据您要解决的问题,您应该考虑使用接口来解耦您的类/模块。
答案 6 :(得分:0)
您的代码仍在执行冗余检查。如果要最小化它们,请使用(T) x
强制转换语法而不是as
。但是,此仍然需要在投射时执行一次检查,这是无法避免的。
也就是说,对于深度嵌套的层次结构(使用is
需要遍历类型层次结构),使用枚举可以比is
更有效。对于平面层次结构,它不太可能更有效,因此您可以直接使用转换。
注意:由于as
中隐式执行的检查,不合并is
和as
- 这是一个反模式。而是使用以下模式:
myInheritedObject1 x = myObject as myInheritedObject1;
if (x != null) {
// …
}
与使用is
/ as
相比,这避免了一次冗余类型检查。
但是,最好的方法是不要进行投射并尽可能使用虚拟方法。