C# 中的 Cast 删除实现的成员数组

Cast drops Implemented Member array in C#

考虑:

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 将不允许 public setter。关于如何实现这一点有什么想法吗?

这就是所谓的“shadowing”。

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

我认为您需要重新考虑您的设计,但您可以通过从子项 class:

中删除 属性 来解决此问题
class Order
{
    public Order()
    {
        OrderItems = new List<OrderItem>();
    }
    public List<OrderItem> OrderItems {get;set;}
}

class SalesOrder : Order { }

class OrderItem {}

class SalesOrderItem : OrderItem {}

另一种选择是使 Order 成为通用的 class:

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 存储特定类型的订单项而不是最一般的类型。

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

在您的代码中,您试图从 Order 导出 SalesOrder。这是最重要的错误:它违反了 Liskov substitution principle。特别是,这意味着派生 class 可能不会向其成员的签名添加额外的约束。请注意,您的 SalesOrder class 确实 添加了这样一个约束:订单商品的类型必须为 SalesOrderItem,而 Order class 接受来自 OrderItem.

的所有订单项目

您想要的是专业化:SalesOrder class 比 Order class 更严格:它只能包含 SalesOrderItems。专业化是通过使用泛型来实现的。所以你可以定义你的 classes 如下:

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> 派生的,你可以这样写:

var order = new SalesOrder();
AddOrderItem(order);

但是,这会导致类型错误,因为 SalesOrder 不能包含普通的 OrderItem。现在,如果您将 SalesOrder 转换为 Order 的唯一原因是 读取 orderitems,您可以引入一个接口:

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 对象转换为 IOrder 并读取订单项。