views:

39

answers:

2

In the class fooBase there is SomeProperty. In the class barBase, I have a field of type fooBase:

public class fooBase 
{
    public object SomeProperty { get; set; }
}

public class barBase
{
    protected fooBase _foo;
}

It's clear that from barBase I can change SomeProperty by _foo.SomeProperty = whatever;.

Now in the derived class fooChild there is some unimportant logic on which the derived class barChild operates. The barChild constructor gets an instance of fooChild and stores it.

public class fooChild : fooBase { /* someLogic */ }

public class barChild : barBase
{
    public barChild(fooChild foo)
    {
        _foo = foo; // foo of [fooChild] type stored in _foo of [fooBase] type.
    }

    protected fooChild _getFoo // cast via 'as' to access fooChild logic
    { get { return _foo as fooChild; } }
}

Now to use the logic of fooChild, I need to access _foo as fooChild (which _getFoo does).

Question: Will the get { return ... as ... } create a local copy of _foo, so that when I call SomeFunction() in a derived class of barChild, the property change SomeProperty will not happen in the barBase._foo?

public class somewhereElse : barChild
{
    public void SomeFunction()
    {
        _getFoo.SomeProperty = new object();
        // now barBase:_foo.SomeProperty is still old object?
    }
}

If yes, how can I avoid that?
If no, how can I tell?

A: 

"as" keyword never creates new object (why should it?), so SomeProperty is new object

(MySubClass)myInstance

myInstance as MySubClass

this is almost the same (and niether will create new instances)
(it's not the same if myInstance is not typeof MySubclass, in that case first line will throw exception and on the second line the "as operator" will return null)

Kikaimaru
So although _getFoo only has 'get' implemented the underlying field can still be modified?
Martin
as long as you are returning class and not struct (valuetype) then yes --- what get acctualy does is generate method fooChild _getFoo_get() so it will return reference to a fooChild and you can do whatever you want with it (change properties, etc) --- but without setter you cannot change the _foo field inside barChild
Kikaimaru
+1  A: 

The only time a reference type is copied is when you call a method or property that actively makes a copy. Clone() being the obvious example (with some exceptions, with an immutable type like string it's safe for Clone() to just return the same object and pretend its a new one, as nothing can change either).

as is always an identity cast. x = obj as T is equivalent to:

if(obj is T)
  x = (T)(object)obj;
else
  x = null;

The reason I have (T)(object) there instead of just (T) is that sometimes an implicit cast operator will exist for casting between two types, and that may create a new object. Casting to and from object won't (unless someone's been foolish with cast operators - I'm pretty sure the compiler will stop them if they are that foolish, but it's so silly a case I can't be bothered testing, just don't write casts to and from object).

If you want to test if an object is the same as another object use ReferenceEquals, this compares solely for identity, even if Equals is overridden, or the arguments are boxed value types.

Jon Hanna
+1 for the thoroughness of your answer :)
Martin