Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# - Does casting preserve the reference to the original object?

Tags:

c#

If I cast an object in C#, does it still reference the original object cast?

As an example, if I create a method to change an object and then cast that object depending on specific implementation called, does the original object get preserved?

    public bool CallChangeString()
    {
        String str = "hello";
        ChangeObject(str);
        return String.Equals("HELLO", str);
    }

    public void ChangeObject(Object obj)
    {
        String str = obj as String;
        str.ToUpper(); // pretend for the sake of this that this changes str to upper case
    }

In this case, would the String.Equals return true or false?

Are there any situations where casting would cause the new object to not preserve it's reference?

like image 754
Shub-Nullgurath Avatar asked Jan 20 '17 10:01

Shub-Nullgurath


1 Answers

Depends on what cast you are doing. You can think of two main groups of casting:

  1. Those that preserve identity
  2. Those that don't

Well, thats not very helpful, that is precisely what you are asking.

What casts don't preserve identity? All those that entail a representational change in the object itself, that is, the bits that make up the object change.

Examples? All casts between value types: int to long, int to double, etc., any boxing or unboxing conversion, etc. The bits that make up a long are very different from those that make up an int.

More examples? Any user defined cast operator, explicit or implicit. Why? Because user defined casts that preserve identity are disallowed by the compiler simply because the compiler already does them for you:

class Foo : IFoo
{
     public static implicit operator object(Foo foo) => return foo; //Compile time error     
     public static implicit operator IFoo(Foo foo) => return foo; //compile time error.

     public static explicit operator Bar(Foo foo) => return new Bar(foo);
}

Note the general pattern of user defined casts:

  • any valid operator will always have a new lurking around in whatever it returns. Thats telling you right away that the cast can not preserve identity... you are returning a new object.
  • There is no way you can implement a user defined identity preserving conversion. Thats not a problem because there is no need, those conversions are already provided by C#'s type system.

So, what are identity preserving casts or conversions? Well, those that don't touch the object all; reference conversions.

Huh? But wait, The whole point is that I'm casting the object, how can that be?

In reference conversions you are only "casting" the reference pointing to the object. The object is always the same. This, of course, only makes sense in reference types and that is why value types don't have identity preserving conversions; there are no references to value types unless they are boxed.

Examples? object to string, Foo to IFoo, Giraffe to Animal, etc.

Do note that reference types can very well implement user defined casts too, but these will not preserve identity.

All that said, this is the rule of the thumb:

  • Any cast provided/allowed by the language type system itself preserves identity. These are, exclusively, reference conversions and only apply to reference types.
  • Any user defined cast, explicit or implicit, does not preserve identity (rememeber, (long)2 is a user defined cast, somebody had to implement it in the class System.Int64).

So, answering your question, var str = obj as string is a reference conversion, which means that ReferenceEquals(str, obj) is true; str and obj point to exactly the same object, the only difference is the type of the reference.

like image 148
InBetween Avatar answered Sep 23 '22 21:09

InBetween