Considering the following sample code:
考虑以下示例代码:
// delivery strategies
public abstract class DeliveryStrategy { ... }
public class ParcelDelivery : DeliveryStrategy { ... }
public class ShippingContainer : DeliveryStrategy { ... }
and the following sample Order class:
和以下示例Order类:
// order (base) class
public abstract class Order
{
private DeliveryStrategy delivery;
protected Order(DeliveryStrategy delivery)
{
this.delivery = delivery;
}
public DeliveryStrategy Delivery
{
get { return delivery; }
protected set { delivery = value; }
}
}
When i derive a new type of order class, it will inherit the Delivery property of type DeliveryStrategy.
当我派生出一种新类型的订单类时,它将继承DeliveryStrategy类型的Delivery属性。
Now, when it is given that CustomerOrders must be delivered using the ParcelDelivery strategy, we could consider 'new'ing the Delivery property in the CustomerOrder class:
现在,当给出必须使用ParcelDelivery策略交付CustomerOrders时,我们可以考虑在CustomerOrder类中“新建”Delivery属性:
public class CustomerOrder : Order
{
public CustomerOrder()
: base(new ParcelDelivery())
{ }
// 'new' Delivery property
public new ParcelDelivery Delivery
{
get { return base.Delivery as ParcelDelivery; }
set { base.Delivery = value; }
}
}
(The CustomerOrder obviously needs to ensure that is compatible (polymorph) with Order)
(CustomerOrder显然需要确保与Order兼容(polymorph))
This allows direct usage of the ParcelDelivery strategy on CustomerOrder without the need for casting.
这允许在CustomerOrder上直接使用ParcelDelivery策略,而无需进行强制转换。
Would you consider using this pattern? why / why not?
你会考虑使用这种模式吗?为什么/为什么不呢?
Update: i came up with this pattern, instead of using generics, because i want to use this for multiple properties. I don't want to use generic type arguments for all these properties
更新:我提出了这种模式,而不是使用泛型,因为我想将它用于多个属性。我不想对所有这些属性使用泛型类型参数
8 个解决方案
#1
I think this is a good pattern. It makes it easier to explicitly use derived types by removing the need to cast the result, and it doesn't 'break' the base class behavior. Actually, a similar pattern is used in some classes in the BCL, for instance look at the DbConnection class hierarchy :
我认为这是一个很好的模式。通过消除转换结果的需要,它可以更容易地显式使用派生类型,并且它不会“破坏”基类行为。实际上,在BCL的某些类中使用了类似的模式,例如,查看DbConnection类层次结构:
- DbConnection.CreateCommand() returns a DbCommand
- SqlConnection.CreateCommand() hides the base implementation using 'new' to return a SqlCommand.
- (other DbConnection implementations do the same)
DbConnection.CreateCommand()返回一个DbCommand
SqlConnection.CreateCommand()使用'new'隐藏基本实现以返回SqlCommand。
(其他DbConnection实现也这样做)
So, if you manipulate the connection object through a DbConnection variable, CreateCommand will return a DbCommand ; if you manipulate it through a SqlConnection variable, CreateCommand will return a SqlCommand, avoiding the cast if you're assigning it to a SqlCommand variable.
因此,如果您通过DbConnection变量操作连接对象,CreateCommand将返回DbCommand;如果你通过SqlConnection变量操作它,CreateCommand将返回一个SqlCommand,如果你将它分配给一个SqlCommand变量,则避免使用它。
#2
I'd prefer to make the type generic:
我更喜欢使类型通用:
public abstract class Order<TDelivery> where TDelivery : Delivery
{
public TDelivery Delivery { ... }
...
}
public class CustomerOrder : Order<ParcelDelivery>
{
...
}
This ensures type safety at compile-time, rather than leaving it up to execution time. It also prevents the situation of:
这确保了编译时的类型安全性,而不是将其留待执行时间。它还可以防止以下情况:
CustomerOrder customerOrder = new CustomerOrder();
Order order = customerOrder;
order.Delivery = new NonParcelDelivery(); // Succeeds!
ParcelDelivery delivery = customerOrder.Delivery; // Returns null
Ouch.
I regard new
as usually a last resort. It introduces added complexity both in terms of implementation and use.
我认为新通常是最后的手段。它在实现和使用方面引入了额外的复杂性。
If you don't want to go down the generic route, I'd introduce a genuinely new property (with a different name).
如果您不想沿着通用路线走下去,我会介绍一个真正的新房产(名称不同)。
#3
You can use generics.
你可以使用泛型。
// order (base) class
public abstract class Order<TDeliveryStrategy> where TDeliveryStrategy : DeliveryStrategy
{
private TDeliveryStrategy delivery;
protected Order(TDeliveryStrategy delivery)
{
this.delivery = delivery;
}
public TDeliveryStrategy Delivery
{
get { return delivery; }
protected set { delivery = value; }
}
}
public class CustomerOrder : Order<ParcelDelivery>
{
public CustomerOrder()
: base(new ParcelDelivery())
{ }
}
#4
Using the 'new' keyword to hide writable properties from the base class is a bad idea in my opinion. The new keyword allows you to hide a member of a base class in a derived class, rather than override it. This means that calls to such members using a base-class reference still access the base class code, not derived class code. C# has the 'virtual' keyword, which allows derived classes to actually override the implementation, rather than simply hiding it. There's a reasonably good article here that talks about the differences.
在我看来,使用'new'关键字隐藏基类中的可写属性是个坏主意。 new关键字允许您在派生类中隐藏基类的成员,而不是覆盖它。这意味着使用基类引用对这些成员的调用仍然访问基类代码,而不是派生类代码。 C#具有'virtual'关键字,允许派生类实际覆盖实现,而不是简单地隐藏它。这里有一篇相当不错的文章讨论了这些差异。
In your case, it looks like you are trying to use method hiding as a way of introducing property covariance to C#. However, there are problems with this approach.
在您的情况下,您似乎尝试使用方法隐藏作为向C#引入属性协方差的方法。但是,这种方法存在问题。
Often, the value of having a base class is to allow users of your code to treat types polymorphically. What happens with your implementation if someone sets the Delivery property using a reference to the base class? Will the derived class break if the Delivery property is NOT an instance of ParcelDelivery? These are the kinds of questions you need to ask yourself about this choice of implementation.
通常,拥有基类的价值在于允许代码的用户以多态方式处理类型。如果有人使用对基类的引用设置Delivery属性,您的实现会发生什么?如果Delivery属性不是ParcelDelivery的实例,派生类是否会中断?这些是您需要问自己这种实施选择的问题。
Now, if the Delivery property in the base class did not supply a setter, then you have a slightly different situation. Users of the base class can only retrieve the property and not set it. Since you route your property access back to the base class, access through the base class continues to work. However, if your derived class is not sealed, classes that inherit from it could introduce the same types of problems by hiding the Delivery property with a version of their own.
现在,如果基类中的Delivery属性没有提供setter,那么您的情况会略有不同。基类的用户只能检索属性而不能设置它。由于您将属性访问路由回基类,因此通过基类访问仍然有效。但是,如果派生类未被密封,则从中继承的类可能会通过将Delivery属性隐藏为自己的版本来引入相同类型的问题。
As some of the other posts have already mentioned, you could use generics as a way to achieve different Delivery property types. Jon's example is pretty good at demonstrating this. There is one problem with the approach of generics, if you need to derive from CustomerOrder and change the Delivery property to a new type.
正如其他一些帖子已经提到的那样,您可以使用泛型作为实现不同Delivery属性类型的方法。乔恩的例子非常擅长证明这一点。如果您需要从CustomerOrder派生并将Delivery属性更改为新类型,则泛型方法存在一个问题。
There is an alternative to generics. You need to consider whether you really want a settable property in your case. If you get rid of the setter on the Delivery property, the issues introduced by using the Order class directly go away. Since you set the delivery property using constructor parameters, you can guarantee that all orders have the right type of strategy.
有一种替代仿制药。你需要考虑你是否真的想要一个可设置的属性。如果你摆脱了Delivery属性的setter,使用Order类引入的问题就会消失。由于您使用构造函数参数设置交付属性,因此可以保证所有订单都具有正确的策略类型。
#5
Is there any reason why you need to have the return type change? If there isn't then I would suggest just making the Delivery property virtual so it has to be defined by inherited classes instead:
您有什么理由需要更改返回类型吗?如果没有,那么我建议只将交付属性设置为虚拟,因此必须由继承的类来定义:
public abstract class Order
{
protected Order(DeliveryStrategy delivery)
{
Delivery = delivery;
}
public virtual DeliveryStrategy Delivery { get; protected set; }
}
public class CustomerOrder : Order
{
public CustomerOrder()
: base(new ParcelDelivery())
{ }
public DeliveryStrategy Delivery { get; protected set; }
}
If you do require the change in return type, then I would wonder why you would need that drastic of a behavior change on the return type. Regardless, if that is so, then this won't work for you.
如果你确实需要改变返回类型,那么我想知道为什么你需要在返回类型上改变行为。无论如何,如果是这样,那么这对你不起作用。
So to directly answer your question, I would only use the pattern you've described if it is required that the return type be different from the base class, and very sparingly (I would analyze my object model to see if there's something else i could do first). If that is not the case, then I would use the pattern I've described above.
所以要直接回答你的问题,我只会使用你所描述的模式,如果要求返回类型与基类不同,并且非常谨慎(我会分析我的对象模型,看看是否还有其他的东西我可以先做)。如果不是这样,那么我会使用我上面描述的模式。
#6
Consider this approach:
考虑这种方法:
public interface IOrder
{
public DeliveryStrategy Delivery
{
get;
}
}
// order (base) class
public abstract class Order : IOrder
{
protected readonly DeliveryStrategy delivery;
protected Order(DeliveryStrategy delivery)
{
this.delivery = delivery;
}
public DeliveryStrategy Delivery
{
get { return delivery; }
}
}
then use
public class CustomerOrder : Order
{
public CustomerOrder()
: base(new ParcelDelivery())
{ }
public ParcelDelivery Delivery
{
get { return (ParcelDelivery)base.Delivery; }
}
DeliveryStrategy IOrder.Delivery
{
get { return base.Delivery}
}
}
This is still far from perfect (your example doesn't show why the base class needs to know about the delivery strategy at all and it would make much more sense to be generic with a constraint but this at least allows you to use the same name for the property and get type safety.
这仍然远非完美(你的例子没有说明为什么基类需要了解交付策略,并且通过约束更通常会更有意义但这至少允许你使用相同的名称对于财产和获得类型安全。
The as in your example was pointless, if something is ever not the right type you should not mask it with null you should throw as your invariant has been violated.
你的例子中的as是毫无意义的,如果某些东西不是正确的类型,你不应该用null掩盖它,你应该抛弃你的不变量。
readonly fields are always preferable where possible. They make the immutability clear.
在可能的情况下,只读字段总是更好。它们使不变性变得清晰。
#7
Your solution does not do what you think it does. It appears to work but it is not calling your "new" method. Consider the following changes to your code to add some output to see which method is called:
您的解决方案没有按照您的想法执行。它似乎工作,但它没有调用你的“新”方法。考虑对代码进行以下更改以添加一些输出以查看调用的方法:
// order (base) class
public abstract class Order
{
private DeliveryStrategy delivery;
protected Order(DeliveryStrategy delivery)
{
this.delivery = delivery;
}
public DeliveryStrategy Delivery
{
get
{
Console.WriteLine("Order");
return delivery;
}
protected set { delivery = value; }
}
}
public class CustomerOrder : Order
{
public CustomerOrder()
: base(new ParcelDelivery())
{ }
// 'new' Delivery property
public new ParcelDelivery Delivery
{
get
{
Console.WriteLine("CustomOrder");
return base.Delivery as ParcelDelivery;
}
set { base.Delivery = value; }
}
}
Then the following snippet of code to actually use your CustomOrder class:
然后使用以下代码片段实际使用您的CustomOrder类:
Order o = new CustomerOrder();
var d = o.Delivery;
Would output the "Order". The new method specifically breaks polymorphism. It creates a new Delivery property on CustomOrder that is not part of the Order base class. So when you use your CustomOrder as if it were an Order, you do not call the new Delivery property because that only exists on CustomOrder and is not part of the Order class.
会输出“订单”。新方法特别打破了多态性。它在CustomOrder上创建一个新的Delivery属性,该属性不是Order基类的一部分。因此,当您使用CustomOrder时,就好像它是一个Order,您不会调用新的Delivery属性,因为它只存在于CustomOrder上,并且不是Order类的一部分。
What you're trying to do is override a method that isn't overridable. If you mean the property to be overridable, make it abstract:
您要做的是覆盖不可覆盖的方法。如果您的意思是要覆盖的属性,请将其设为抽象:
// order (base) class
public abstract class Order
{
private DeliveryStrategy delivery;
protected Order(DeliveryStrategy delivery)
{
this.delivery = delivery;
}
public abstract DeliveryStrategy Delivery
{
get { return delivery; }
protected set { delivery = value; }
}
}
public class CustomerOrder : Order
{
public CustomerOrder()
: base(new ParcelDelivery())
{ }
public override ParcelDelivery Delivery
{
get { return base.Delivery as ParcelDelivery; }
set { base.Delivery = value; }
}
}
#8
Using new
to shadow virtual members of a base class is a bad idea, because sub-derived types will not be able to override them properly. If there exist class members which one will want to shadow in derived classes, the base class members should not be declared as abstract
or virtual
, but should instead simply call a protected abstract
or protected virtual
member. A derived type can shadow the base-class method with one that calls the appropriate protected
member and casts the result appropriately.
使用new to shadow基类的虚拟成员是一个坏主意,因为子派生类型将无法正确覆盖它们。如果存在要在派生类中影响的类成员,则不应将基类成员声明为抽象或虚拟,而应简单地调用受保护的抽象或受保护的虚拟成员。派生类型可以使用调用相应受保护成员的方法来遮蔽基类方法并适当地转换结果。
#1
I think this is a good pattern. It makes it easier to explicitly use derived types by removing the need to cast the result, and it doesn't 'break' the base class behavior. Actually, a similar pattern is used in some classes in the BCL, for instance look at the DbConnection class hierarchy :
我认为这是一个很好的模式。通过消除转换结果的需要,它可以更容易地显式使用派生类型,并且它不会“破坏”基类行为。实际上,在BCL的某些类中使用了类似的模式,例如,查看DbConnection类层次结构:
- DbConnection.CreateCommand() returns a DbCommand
- SqlConnection.CreateCommand() hides the base implementation using 'new' to return a SqlCommand.
- (other DbConnection implementations do the same)
DbConnection.CreateCommand()返回一个DbCommand
SqlConnection.CreateCommand()使用'new'隐藏基本实现以返回SqlCommand。
(其他DbConnection实现也这样做)
So, if you manipulate the connection object through a DbConnection variable, CreateCommand will return a DbCommand ; if you manipulate it through a SqlConnection variable, CreateCommand will return a SqlCommand, avoiding the cast if you're assigning it to a SqlCommand variable.
因此,如果您通过DbConnection变量操作连接对象,CreateCommand将返回DbCommand;如果你通过SqlConnection变量操作它,CreateCommand将返回一个SqlCommand,如果你将它分配给一个SqlCommand变量,则避免使用它。
#2
I'd prefer to make the type generic:
我更喜欢使类型通用:
public abstract class Order<TDelivery> where TDelivery : Delivery
{
public TDelivery Delivery { ... }
...
}
public class CustomerOrder : Order<ParcelDelivery>
{
...
}
This ensures type safety at compile-time, rather than leaving it up to execution time. It also prevents the situation of:
这确保了编译时的类型安全性,而不是将其留待执行时间。它还可以防止以下情况:
CustomerOrder customerOrder = new CustomerOrder();
Order order = customerOrder;
order.Delivery = new NonParcelDelivery(); // Succeeds!
ParcelDelivery delivery = customerOrder.Delivery; // Returns null
Ouch.
I regard new
as usually a last resort. It introduces added complexity both in terms of implementation and use.
我认为新通常是最后的手段。它在实现和使用方面引入了额外的复杂性。
If you don't want to go down the generic route, I'd introduce a genuinely new property (with a different name).
如果您不想沿着通用路线走下去,我会介绍一个真正的新房产(名称不同)。
#3
You can use generics.
你可以使用泛型。
// order (base) class
public abstract class Order<TDeliveryStrategy> where TDeliveryStrategy : DeliveryStrategy
{
private TDeliveryStrategy delivery;
protected Order(TDeliveryStrategy delivery)
{
this.delivery = delivery;
}
public TDeliveryStrategy Delivery
{
get { return delivery; }
protected set { delivery = value; }
}
}
public class CustomerOrder : Order<ParcelDelivery>
{
public CustomerOrder()
: base(new ParcelDelivery())
{ }
}
#4
Using the 'new' keyword to hide writable properties from the base class is a bad idea in my opinion. The new keyword allows you to hide a member of a base class in a derived class, rather than override it. This means that calls to such members using a base-class reference still access the base class code, not derived class code. C# has the 'virtual' keyword, which allows derived classes to actually override the implementation, rather than simply hiding it. There's a reasonably good article here that talks about the differences.
在我看来,使用'new'关键字隐藏基类中的可写属性是个坏主意。 new关键字允许您在派生类中隐藏基类的成员,而不是覆盖它。这意味着使用基类引用对这些成员的调用仍然访问基类代码,而不是派生类代码。 C#具有'virtual'关键字,允许派生类实际覆盖实现,而不是简单地隐藏它。这里有一篇相当不错的文章讨论了这些差异。
In your case, it looks like you are trying to use method hiding as a way of introducing property covariance to C#. However, there are problems with this approach.
在您的情况下,您似乎尝试使用方法隐藏作为向C#引入属性协方差的方法。但是,这种方法存在问题。
Often, the value of having a base class is to allow users of your code to treat types polymorphically. What happens with your implementation if someone sets the Delivery property using a reference to the base class? Will the derived class break if the Delivery property is NOT an instance of ParcelDelivery? These are the kinds of questions you need to ask yourself about this choice of implementation.
通常,拥有基类的价值在于允许代码的用户以多态方式处理类型。如果有人使用对基类的引用设置Delivery属性,您的实现会发生什么?如果Delivery属性不是ParcelDelivery的实例,派生类是否会中断?这些是您需要问自己这种实施选择的问题。
Now, if the Delivery property in the base class did not supply a setter, then you have a slightly different situation. Users of the base class can only retrieve the property and not set it. Since you route your property access back to the base class, access through the base class continues to work. However, if your derived class is not sealed, classes that inherit from it could introduce the same types of problems by hiding the Delivery property with a version of their own.
现在,如果基类中的Delivery属性没有提供setter,那么您的情况会略有不同。基类的用户只能检索属性而不能设置它。由于您将属性访问路由回基类,因此通过基类访问仍然有效。但是,如果派生类未被密封,则从中继承的类可能会通过将Delivery属性隐藏为自己的版本来引入相同类型的问题。
As some of the other posts have already mentioned, you could use generics as a way to achieve different Delivery property types. Jon's example is pretty good at demonstrating this. There is one problem with the approach of generics, if you need to derive from CustomerOrder and change the Delivery property to a new type.
正如其他一些帖子已经提到的那样,您可以使用泛型作为实现不同Delivery属性类型的方法。乔恩的例子非常擅长证明这一点。如果您需要从CustomerOrder派生并将Delivery属性更改为新类型,则泛型方法存在一个问题。
There is an alternative to generics. You need to consider whether you really want a settable property in your case. If you get rid of the setter on the Delivery property, the issues introduced by using the Order class directly go away. Since you set the delivery property using constructor parameters, you can guarantee that all orders have the right type of strategy.
有一种替代仿制药。你需要考虑你是否真的想要一个可设置的属性。如果你摆脱了Delivery属性的setter,使用Order类引入的问题就会消失。由于您使用构造函数参数设置交付属性,因此可以保证所有订单都具有正确的策略类型。
#5
Is there any reason why you need to have the return type change? If there isn't then I would suggest just making the Delivery property virtual so it has to be defined by inherited classes instead:
您有什么理由需要更改返回类型吗?如果没有,那么我建议只将交付属性设置为虚拟,因此必须由继承的类来定义:
public abstract class Order
{
protected Order(DeliveryStrategy delivery)
{
Delivery = delivery;
}
public virtual DeliveryStrategy Delivery { get; protected set; }
}
public class CustomerOrder : Order
{
public CustomerOrder()
: base(new ParcelDelivery())
{ }
public DeliveryStrategy Delivery { get; protected set; }
}
If you do require the change in return type, then I would wonder why you would need that drastic of a behavior change on the return type. Regardless, if that is so, then this won't work for you.
如果你确实需要改变返回类型,那么我想知道为什么你需要在返回类型上改变行为。无论如何,如果是这样,那么这对你不起作用。
So to directly answer your question, I would only use the pattern you've described if it is required that the return type be different from the base class, and very sparingly (I would analyze my object model to see if there's something else i could do first). If that is not the case, then I would use the pattern I've described above.
所以要直接回答你的问题,我只会使用你所描述的模式,如果要求返回类型与基类不同,并且非常谨慎(我会分析我的对象模型,看看是否还有其他的东西我可以先做)。如果不是这样,那么我会使用我上面描述的模式。
#6
Consider this approach:
考虑这种方法:
public interface IOrder
{
public DeliveryStrategy Delivery
{
get;
}
}
// order (base) class
public abstract class Order : IOrder
{
protected readonly DeliveryStrategy delivery;
protected Order(DeliveryStrategy delivery)
{
this.delivery = delivery;
}
public DeliveryStrategy Delivery
{
get { return delivery; }
}
}
then use
public class CustomerOrder : Order
{
public CustomerOrder()
: base(new ParcelDelivery())
{ }
public ParcelDelivery Delivery
{
get { return (ParcelDelivery)base.Delivery; }
}
DeliveryStrategy IOrder.Delivery
{
get { return base.Delivery}
}
}
This is still far from perfect (your example doesn't show why the base class needs to know about the delivery strategy at all and it would make much more sense to be generic with a constraint but this at least allows you to use the same name for the property and get type safety.
这仍然远非完美(你的例子没有说明为什么基类需要了解交付策略,并且通过约束更通常会更有意义但这至少允许你使用相同的名称对于财产和获得类型安全。
The as in your example was pointless, if something is ever not the right type you should not mask it with null you should throw as your invariant has been violated.
你的例子中的as是毫无意义的,如果某些东西不是正确的类型,你不应该用null掩盖它,你应该抛弃你的不变量。
readonly fields are always preferable where possible. They make the immutability clear.
在可能的情况下,只读字段总是更好。它们使不变性变得清晰。
#7
Your solution does not do what you think it does. It appears to work but it is not calling your "new" method. Consider the following changes to your code to add some output to see which method is called:
您的解决方案没有按照您的想法执行。它似乎工作,但它没有调用你的“新”方法。考虑对代码进行以下更改以添加一些输出以查看调用的方法:
// order (base) class
public abstract class Order
{
private DeliveryStrategy delivery;
protected Order(DeliveryStrategy delivery)
{
this.delivery = delivery;
}
public DeliveryStrategy Delivery
{
get
{
Console.WriteLine("Order");
return delivery;
}
protected set { delivery = value; }
}
}
public class CustomerOrder : Order
{
public CustomerOrder()
: base(new ParcelDelivery())
{ }
// 'new' Delivery property
public new ParcelDelivery Delivery
{
get
{
Console.WriteLine("CustomOrder");
return base.Delivery as ParcelDelivery;
}
set { base.Delivery = value; }
}
}
Then the following snippet of code to actually use your CustomOrder class:
然后使用以下代码片段实际使用您的CustomOrder类:
Order o = new CustomerOrder();
var d = o.Delivery;
Would output the "Order". The new method specifically breaks polymorphism. It creates a new Delivery property on CustomOrder that is not part of the Order base class. So when you use your CustomOrder as if it were an Order, you do not call the new Delivery property because that only exists on CustomOrder and is not part of the Order class.
会输出“订单”。新方法特别打破了多态性。它在CustomOrder上创建一个新的Delivery属性,该属性不是Order基类的一部分。因此,当您使用CustomOrder时,就好像它是一个Order,您不会调用新的Delivery属性,因为它只存在于CustomOrder上,并且不是Order类的一部分。
What you're trying to do is override a method that isn't overridable. If you mean the property to be overridable, make it abstract:
您要做的是覆盖不可覆盖的方法。如果您的意思是要覆盖的属性,请将其设为抽象:
// order (base) class
public abstract class Order
{
private DeliveryStrategy delivery;
protected Order(DeliveryStrategy delivery)
{
this.delivery = delivery;
}
public abstract DeliveryStrategy Delivery
{
get { return delivery; }
protected set { delivery = value; }
}
}
public class CustomerOrder : Order
{
public CustomerOrder()
: base(new ParcelDelivery())
{ }
public override ParcelDelivery Delivery
{
get { return base.Delivery as ParcelDelivery; }
set { base.Delivery = value; }
}
}
#8
Using new
to shadow virtual members of a base class is a bad idea, because sub-derived types will not be able to override them properly. If there exist class members which one will want to shadow in derived classes, the base class members should not be declared as abstract
or virtual
, but should instead simply call a protected abstract
or protected virtual
member. A derived type can shadow the base-class method with one that calls the appropriate protected
member and casts the result appropriately.
使用new to shadow基类的虚拟成员是一个坏主意,因为子派生类型将无法正确覆盖它们。如果存在要在派生类中影响的类成员,则不应将基类成员声明为抽象或虚拟,而应简单地调用受保护的抽象或受保护的虚拟成员。派生类型可以使用调用相应受保护成员的方法来遮蔽基类方法并适当地转换结果。