【问题标题】:C# Pass by reference items in List<T>C# 传递 List<T> 中的引用项
【发布时间】:2016-01-30 17:30:39
【问题描述】:

在开发我的简单 ORM 时,我需要用它的代理替换 POCO,因此我编写了一些方法来使用我的 ProxyBuilder 处理 POCO 列表,以创建扩展 POCO 并实现 IEntity 的代理,然后用新的代理重新分配 POCO 对象,但同时这样做,我在重新分配 POCO 列表中的项目后投射对象时遇到错误,它说'无法将'Order'类型的对象投射到'IEntity'类型

我用一些类简化了我的代码,如下所示:

public class Order
{
    public string Code { get; set; }
    public string Description { get; set; }
    public DateTime Date { get; set; }
    public decimal Total { get; set; }
}

interface IEntity
{
    public long ID;
}

public class OrderProxy : Order, IEntity
{
    // some functions of a proxy 
}

然后使用这样的代码

public void Run()
{
    Order order1 = new Order() { .... }; 
    Order order2 = new Order() { .... };
    List<Order> orders = new List<Order>();
    items.Add(order1);
    items.Add(order2);

    Process<Order>(orders);

    // ERROR occured here 'Unable to cast object of type 'Order' to type 'IEntity' 
    ((IEntity)order1).ID= 1; 
}

public void Process<T>(List<T> items)
{
    for (int i = 0; i < items.Count; i++)
    {
        items[i] = (T)CreateProxy();
    }
}

private object CreateProxy(object obj)
{
    // my ProxyBuilder will create new instance of OrderProxy depend on passed POCO parameter then return it
    return new OrderProxy();
}

我知道带有 T 的 List 是类,将通过引用传递,但在这种情况下,我不明白为什么它不能,列表变量 orders 处理后包含我想要的代理,但是order 实例仍然不是代理,我可能错过了什么吗?或者任何人帮助我改变我的代码中处理 List 的方式来获得这个,提前感谢

【问题讨论】:

  • @qxg 为什么该行会有异常?
  • @Thomas,我刚刚注意到OrderProxy : Order。我错了。
  • @qxg 啊可以发生。你让我想知道是否有什么我不知道的。
  • @lLeQuangHoa 您是否修改了问题,使其现在变成了 2 个不同的问题? (“我在重新分配 POCO 列表中的项目后投射对象时遇到错误,它说'无法将'Order'类型的对象投射到'IEntity'类型”)。如果是这样,你有一个额外的问题不是直接源于第一个问题,你应该创建 2 个问题,因为其他所有问题都令人困惑。
  • 为什么是对象类型的CreateProxy??????也许您应该使用通用方法。 private U CreateProxy(T argument) where T : Order etc

标签: c#


【解决方案1】:

您正在尝试投射错误的东西,在您调用 Process 之前您所拥有的内容如下:

Order order1
Order order2
List<Order> orders
Order orders[0]
Order orders[1]

调用 Process 后,你有这个:

Order order1
Order order2
List<Order> orders
OrderProxy orders[0]
OrderProxy orders[1]

因此,要将order1 转换为IEntity,您需要通过列表中已“升级”为OrderProxy 的项目执行此操作,因此您需要这样做:

((IEntity)orders[0]).ID= 1;

不是

((IEntity)order1).ID= 1;

【讨论】:

  • 如果是这样,不是我想要的,我希望用户可以创建实例添加到列表,处理它然后实例将是代理
  • 有没有办法在 Process 方法中重新分配项目实例?
【解决方案2】:

因为您将订单中的所有商品替换为其他类型(OrderProxy),所以order1orders[1] 现在是不同的对象。

试试

((IEntity)orders[1]).ID = 1;

如果OrderProxy是这样的

class OrderProxy : Order
{
    public Order Order {get;}

    public OrderProxy(Order o)
    {
         this.Order = o;
    }
}

您仍然可以通过

访问原始订单1
((OrderProxy)orders[1]).Order

【讨论】:

    【解决方案3】:

    调用 Process 后,你有四个不同的对象;

    order1, order2, orders[0], orders[1]
    

    order1 - orders[0] 和 order2 - orders[1] 之间没有关系

    你要找的是orders[0]和orders[1]

    【讨论】:

    • 如果是这样,不是我想要的,我希望用户可以创建实例添加到列表,处理它然后实例将成为代理,有没有办法在 Process 方法中重新分配项目实例?
    【解决方案4】:

    您遇到的问题是 List 本身实际上也只有引用。因此,在 Process 中,您将 items[i] 更改为不再指向 Order 的实例,而是指向 OrderProxy 的实例。

    但这并没有修改 order1 和 order2,因为这两个没有指向特定的项目,而是指向也被项目引用(最初)的订单实例。当您更改引用的项目时,订单 1 和订单 2 不受此更改的影响,因为它们没有指向项目,而是直接指向订单实例。

    编辑: 正如您添加了第二个问题。 您的线路:

    ((IEntity)order1).ID= 1; 
    

    失败,因为 IEntity 用于 ProxyOrder 但 order1 属于 Order 类,并且将始终属于该类,并且该类不是派生 IEntity。因此它不能自动转换为 IEntity(如果你想这样做,你必须编写一个转换方法)。

    【讨论】:

    • 所以,List 实际上只是一个指向项目指针的指针列表?,当更改 List 中的项目时,它只是更改指向其他指针实例的指针?
    • 不,问题是 order1 的运行时类型不是 OrderProxy,强制转换 IEntity 或 OrderProxy 是同一个问题/问题
    • 对于第一条评论:是的,如果您有一个对象(或类)列表,那么这个列表实际上只是一个指向特定实例的指针列表。
    • 第二个是:order1是类order,指向一个具体的实例。您更改列表元素指向的实例对 order1 和 order2 没有影响。因此,这 2 个在运行时仍然指向一个订单对象,并且始终如此。您可以将 order1 或 order2 转换为 proxyorder,然后再转换为 Entity,但由于 Order 本身与 IEntity 没有任何关系,因此您无法正确地将 order1 转换为 IEntity。但由于 OrderProxy 与 Order 相关(派生于),您可以将 order1 转换为 OrderProxy。
    • 不,您不能将 order1 或 2 转换为 OrderProxy,正如我在上面的评论中提到的,我希望您可以尝试调试一次
    猜你喜欢
    • 1970-01-01
    • 2013-11-11
    • 1970-01-01
    • 2018-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-07
    • 1970-01-01
    相关资源
    最近更新 更多