0

When developing my simple ORM, i need to replace POCOs by its proxies, so i code some methods to process list of POCOs with my ProxyBuilder to create proxy which extends POCO and implement IEntity then reassign POCO object with new proxy, but while doing this, i face a error when casting object after reassign item in List of POCOs, it say 'Unable to cast object of type 'Order' to type 'IEntity'

I simplify my code with some classes as followings:

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 
}

Then consuming code like that

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();
}

I've known that List<> with T is class, will passed by references but in this case i dont understand why it cant, the list variable orders after process include proxies as i want but order instance is still not proxy, may be i miss something? or anyone help me change the way process List<> in my code to get this, thank in advance

  • @qxg Why should there be an exception at that line? – Thomas Oct 30 '15 at 10:18
  • @Thomas, I just noticed `OrderProxy : Order`. I'm wrong. – qxg Oct 30 '15 at 10:23
  • @qxg ah can happen. You had me wonder there for a moment if there is something I don't know. – Thomas Oct 30 '15 at 10:25
  • @lLeQuangHoa Did you modify the question so that it is now 2 different ones? ("i face a error when casting object after reassign item in List of POCOs, it say 'Unable to cast object of type 'Order' to type 'IEntity"). If it is so that you have an additional problem that is not directly steming from the first problem you should create 2 questions as all else is confusing. – Thomas Oct 30 '15 at 10:27
  • Why is CreateProxy of type object?????? Maybe you should be using a generic method. private U CreateProxy(T argument) where T : Order etc – RaidenF Oct 30 '15 at 10:27
  • Updated my answer to incoroporate the 2nd question – Thomas Oct 30 '15 at 10:31
  • yes, but i only change is from ((OrderProxy)order1).ID= 1 to ((IEntity)order1).ID= 1; , my mistake, sorry, but not effect to original question, theys have same problem – Le Quang Hoa Oct 30 '15 at 10:33
  • @K.Gkinis, it just simplify version my code, but in my real code CreateProxy still return object because it is a common api for dynamic POCO, Order is just a example – Le Quang Hoa Oct 30 '15 at 10:54

4 Answers4

1

The problem you have is that the List itself also only has references in reality. Thus in Process you change the items[i] to no longer point to an instance of Order but instead to an instance of OrderProxy.

BUT this does not modify order1 and order2 as those two did not point to the specific items but instead to order instances which were also referenced (originally) by the items. When you changed what the items referenced the order1 and order2 are thus unaffected by this change as they did not point to items but directly to the order instances.

Edit: As you have added a second question. Your line:

((IEntity)order1).ID= 1; 

fails because IEntity is used for ProxyOrder BUT order1 is of the class Order and will always be of that class and that class is NOT deriving IEntity. Thus it cannot be automatically converted to IEntity (you would have to write a converting method if you want to do this).

Thomas
  • 2,886
  • 3
  • 34
  • 78
  • so, List is in reality just a list of pointers to pointer of items?, when change item in List it just change pointer to other pointer instances? – Le Quang Hoa Oct 30 '15 at 10:40
  • no, the problem is order1 has runtime type is not OrderProxy, cast IEntity or OrderProxy is the same question/problem – Le Quang Hoa Oct 30 '15 at 10:46
  • For the first comment: Yes if you have a list of objects (or classes) then this list is in reality just a list of pointers pointing onto specific instances. – Thomas Oct 30 '15 at 10:56
  • For the 2nd is: order1 is of the class order and points to a specific instance. That you change the instance to which the list elements points has no effect on order1 and also not on order2. thus these 2 still point to an order object at runtime and always will. You CAN cast order1 or order2 to proxyorder and that then to ientity but as Order itself is not in any way related to IEntity you can't cast order1 to IEntity correctly. But as OrderProxy is related (derived of) Order you can cast order1 to OrderProxy. – Thomas Oct 30 '15 at 11:00
  • no, you CANT cast order1 or 2 to OrderProxy, as i mention in above comment, i hope you can try to debug once – Le Quang Hoa Oct 30 '15 at 11:09
  • oops my fault. Always confusing the derived and base. The problem wirh OrderProxy and order1, 2 is that you can't cast the base class to the derived class automatically (the other way round works though http://stackoverflow.com/questions/12565736/convert-base-class-to-derived-class) Thus you would need to create a new orderproxy object and assign it the values of order 1 or order2 to convert those to orderproxy so to say (for example via constructor). Else sadly no other way. And the IEntity also holds true there. You can cast OrderProxy to IEntity but not Order. – Thomas Oct 30 '15 at 11:15
1

After calling Process you have four different objects;

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

No relationship left between order1 - orders[0] and order2 - orders[1]

What you are looking for are orders[0] and orders[1]

Serif Emek
  • 674
  • 5
  • 13
  • if so, is not my want, i want user can create instance add to list, process it then the instance will be proxy, is there a way to reassign item instance in Process method? – Le Quang Hoa Oct 30 '15 at 11:25
1

Because you replaced all items in orders with other types (OrderProxy), order1 and orders[1] are different objects now.

Try

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

If OrderProxy is like this

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

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

You can still access original order1 by

((OrderProxy)orders[1]).Order
qxg
  • 6,955
  • 1
  • 28
  • 36
1

You are trying to cast the wrong thing, what you have before you call Process is the following:

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

After calling Process, you have this:

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

So in order to cast order1 as an IEntity, you need to do that via the item in the list which has been "upgraded" to an OrderProxy so you need to do this:

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

not

((IEntity)order1).ID= 1;
Trevor Pilley
  • 16,156
  • 5
  • 44
  • 60