C#/ .Net中"新"属性的优缺点?

oɔɯ*_*ɯǝɹ 9 .net c# properties new-operator

考虑以下示例代码:

// delivery strategies
public abstract class DeliveryStrategy { ... }
public class ParcelDelivery : DeliveryStrategy { ... }
public class ShippingContainer : DeliveryStrategy { ... }
Run Code Online (Sandbox Code Playgroud)

和以下示例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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

当我派生出一种新类型的订单类时,它将继承DeliveryStrategy类型的Delivery属性.

现在,当给出CustomerOrders必须使用ParcelDelivery策略交付时,我们可以考虑在CustomerOrder类中" "交付属性:

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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

(CustomerOrder显然需要确保与Order兼容(polymorph))

这允许在CustomerOrder上直接使用ParcelDelivery策略,而无需进行强制转换.

你会考虑使用这种模式吗?为什么/为什么不呢?

更新:我提出了这种模式,而不是使用泛型,因为我想将它用于多个属性.我不想对所有这些属性使用泛型类型参数

Jon*_*eet 11

我更喜欢使类型通用:

public abstract class Order<TDelivery> where TDelivery : Delivery
{
    public TDelivery Delivery { ... }
    ...
}

public class CustomerOrder : Order<ParcelDelivery>
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

这确保了编译时的类型安全性,而不是将其留待执行时间.它还可以防止以下情况:

CustomerOrder customerOrder = new CustomerOrder();
Order order = customerOrder;
order.Delivery = new NonParcelDelivery(); // Succeeds!

ParcelDelivery delivery = customerOrder.Delivery; // Returns null
Run Code Online (Sandbox Code Playgroud)

哎哟.

我认为new通常是最后的手段.它在实现和使用方面引入了额外的复杂性.

如果您不想沿着通用路线走下去,我会介绍一个真正的新房产(名称不同).


Tho*_*que 7

我认为这是一个很好的模式.通过消除转换结果的需要,它可以更容易地显式使用派生类型,并且它不会"破坏"基类行为.实际上,在BCL的某些类中使用了类似的模式,例如查看DbConnection类层次结构:

  • DbConnection.CreateCommand()返回一个DbCommand
  • SqlConnection.CreateCommand()使用'new'隐藏基本实现以返回SqlCommand.
  • (其他DbConnection实现也这样做)

因此,如果您通过DbConnection变量操作连接对象,CreateCommand将返回DbCommand; 如果你通过SqlConnection变量操作它,CreateCommand将返回一个SqlCommand,如果你将它分配给一个SqlCommand变量,则避免强制转换.


TcK*_*cKs 5

你可以使用泛型.

// 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())
    { }
}
Run Code Online (Sandbox Code Playgroud)