考虑:
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
则不允许使用公共设置器。有关如何实现这一点的任何想法?
答案 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
并阅读订单商品。