Schanckopotamus
Schanckopotamus

Reputation: 791

Dynamic object being 'populated' with property that shouldn't exist in the Type that was passed

Alright so I am having an issue with dynamics ... I know they are potentially dangerous but hear me out. Basically I have an object, lets call it Customer.

public class Customer
{
    public int Id { get; set; }
    public string Type { get; set; }
    public string Value { get; set; }
    public bool IsActive { get; set; }
}

I have another object that inherits from this object. Lets call it ImportantCustomer.

public class ImportantCustomer : Customer
{
    public int SomeOtherValue { get; set; }
}

I now have a method that does my magic which has to do something to anything it is given. The method is not part of either class above.

public void DoTheMagic(dynamic myObject)
{
    //My magic here
)

The issue is that a layer up I will be getting the object ImportantCustomer but I want to send it a Customer object. So I do something like this:

var customer = (Customer)importantCustomer;

or

Customer customer = importantCustomer;

or

ICustomer customer = importantCustomer;

Either way of doing it nets me the same result that I don't want. Now I have the object I want to send to my method and everything should be good(a Customer). However, part of the logic in my magic calls another method with an object parameter.

public void SomeOtherMethod(object obj)
{
    //More magic
)

Inside this method it gets all the properties of the object. Which, when stepping through it, it does, however it also gives me the 'SomeOtherValue' property that is in the ImportantCustomer object, but I passed in my new Customer object, which obviously doesn't implement the property. Why is this property being added? Is there some kind of deep down understanding of how this is done that is causing this? Is there something going on with the reference in the background that is causing this property to show up because of the casting to the Customer type?

If I do it the manual way:

var customer = new Customer()
{
    Id = importantCustomer.Id,
    Type = importantCustomer.Type,
    Value = importantCustomer.Value,
    IsActive = importantCustomer.IsActive,
};

It works as intended in the sense that I don't get the 'SomeOtherValue' property in the magic.

I am having a hard time finding an answer/reason why. If there is an answer/explanation on here I missed please point me to it.

Thanks.

EDIT 1

I don't understand why the SomeOtherValue property would still be there after the cast. I get that there is referencing going on but after the class if I where to do this:

var customer = (Customer)importantCustomer;
var value = customer.SomeOtherValue; // ERROR

The compiler gets angry because the the property doesn't exist in the Customer type. I am probably just missing something important with how the casting works, I just don't know what it is.

Update

Is there a better way, other than using AutoMapper or something similar to get the Customer object I want so I wouldn't have to write it out manually?

Thanks @Matt Burland for the explanation it was insightful.

Upvotes: 0

Views: 77

Answers (1)

Matt Burland
Matt Burland

Reputation: 45135

The property is there because it's part of the object you passed. When you do Customer customer = importantCustomer you are copying a reference to an object that is still an ImportantCustomer. Your "manual" casting isn't casting at all. It's copying the object. Casting isn't copying.

So when you do this:

Customer customer = importantCustomer;

It's still an important customer and you can, in fact, cast it back:

ImportantCustomer important = (ImportantCustomer)customer;

But if Customer was an actual Customer (and not ImportantCustomer) the above cast would throw an error.

So no property is being "added" - it was there all along.

Note: You cannot do this:

Customer customer = importantCustomer;
int t = customer.SomeOtherValue;

Because by typing the variable as Customer all you are guaranteeing is that the variable customer will contain a Customer object or something that derives from it. So the compiler can only know, for certain, that the variable customer has all the properties and methods of Customer. Hence, it will give you a compile error in that case. That doesn't mean the object in customer doesn't have the SomeOtherValue property, just that it isn't guaranteed. For example, you might do this:

Customer customer = importantCustomer;
// ...some code
customer = new Customer();
// ...some more code
int t = customer.SomeOtherValue;   // now this is obviously wrong

And keep in mind that reassigning customer to a new Customer might happen in another thread. You could even do it in the debugger.

Upvotes: 3

Related Questions