Cast drop在C#中实现了Member数组

时间:2015-03-18 17:19:00

标签: c# inheritance casting

考虑:

class Order
{
    public List<OrderItem> OrderItems {get;set;}
}

class SalesOrder : Order
{
    public List<SalesOrderItem> OrderItems {get;set;}
}

class OrderItem {}

class SalesOrderItem : OrderItem {}

试图施展时

SalesOrder salesorder = new SalesOrder();
salesorder.OrderItems = List<SalesOrderItem>();
salesorder.OrderItems.Add(new SalesOrderItem());
Order order = salesorder;

order.Orderitems为空。有没有办法让这个演员用于派生属性?

我尝试过使用界面协方差,但之后无法使用List而使用IEnumerable则不允许使用公共设置器。有关如何实现这一点的任何想法?

2 个答案:

答案 0 :(得分:5)

这就是所谓的“shadowing”。

您的salesOrder有两个OrderItems属性 - 一个仅对SalesOrder可见的属性,以及一个仅对Order可见的属性。子类中的OrderItems属性将隐藏在父类中的属性。您正在向一个项目添加项目,然后观察另一个项目。

我认为您需要重新考虑您的设计,但是您可以通过从子类中删除属性来解决此问题:

class Order
{
    public Order()
    {
        OrderItems = new List<OrderItem>();
    }
    public List<OrderItem> OrderItems {get;set;}
}

class SalesOrder : Order { }

class OrderItem {}

class SalesOrderItem : OrderItem {}

另一个选择是使Order成为通用类:

class Order<T> where T: OrderItem
{
    public Order()
    {
        OrderItems = new List<T>();
    }
    public List<T> OrderItems {get;set;}
}

class SalesOrder : Order<SalesOrderItem> { }

class OrderItem {}

class SalesOrderItem : OrderItem {}
SalesOrder salesorder = new SalesOrder();
salesorder.OrderItems.Add(new SalesOrderItem());
Order<SalesOrderItem> order = salesorder;

第二种方法的好处是它允许OrderItems存储特定类型的订单商品而不是最常见的类型。

答案 1 :(得分:3)

您的代码中存在多个错误。看起来你混淆了一些OO概念,以及它们在C#中的实现方式。

在您的代码中,您尝试从SalesOrder派生Order。这是最重要的错误:它违反了Liskov substitution principle。特别是,它意味着派生类可能不会为其成员的签名添加额外的约束。请注意,您的SalesOrder 添加了这样的约束:订单商品必须是SalesOrderItem类型,而Order类接受来自{的所有订单商品{1}}。

您想要的是专业化:OrderItem类比SalesOrder类更严格:它只能包含SalesOrderItems。通过使用泛型来实现专业化。因此,您可以按如下方式定义类:

Order

更新:为了说明为什么无法将public class Order<T> where T: OrderItem { public List<T> OrderItems { get; set; } } public class OrderItem { } public class SalesOrder : Order<SalesOrderItem> { } public class SalesOrderItem : OrderItem { } 转换为SalesOrder,请考虑以下静态方法:

Order<OrderItem>

如果public static void AddOrderItem(Order<OrderItem> order) { var item = new OrderItem(); order.OrderItems.Add(order); } 来自SalesOrder,您可以写下:

Order<OrderItem>

但是,这会导致类型错误,因为SalesOrder不能包含普通的OrderItem。现在,如果您将var order = new SalesOrder(); AddOrderItem(order); 转换为SalesOrder的唯一原因是读取订单项,则可以引入一个界面:

Order

现在您可以将public interface IOrder { IEnumerable<OrderItem> GetItems(); } public class Order<T> : IOrder where T: OrderItem { public List<T> OrderItems { get; set; } public IEnumerable<OrderItem> GetItems() { return this.OrderItems; } } 对象转换为SalesOrder并阅读订单商品。