Pregunta

I have a set of objects inherits from one BaseObject which have some global primitive properties (indexes etc). Now, I have two objects, one of them (the target one) have values only for the base properties and the other (the source, which is one of a set of objects) have values for all other the properties (retrieved from a 3rd party app), but the base one's.

I'm trying to copy all the source object's properties to the target one, but keep the target's base properties' values. In other words – I'm trying to equal the two object's properties' values without deleting anything… target = source; will just delete the target's base indexes… So, I made a method which gets as arguments the two objects (casted to BaseObject) and copy the target's indexes's values to the source befor the copy, like this:

Public void Copy(BaseObject source, BaseObject target)
{
    //Copy all primitive indexes here...
    source.index = target.index;
    source.reference = target.reference;
    etc…

    //Copy the updated object to the target one...    
    target = source;
}

It seems to be ok in debug mode inside the method, but – when my code exits from the method I was surprised to see that although the source object was correctly updated with both, inherited and non-inherited properties, the target one values left unchanged. So, I had to copy the (updated) source into the target again, outside the method, like this:

InheritedObject sourceObj = CreateObjectWithPrimitiveIndexes();
InheritedObject targetObj = GetObjectWithNoIndexesFrom3rdParty();

targetObj.Copy(source: sourceObj, target: targetObj);

//The targetObject is not updated, so I have to re-copy it outside the Copy() method
targetObj = sourceObj;

Can someone explain me why the sourceObj is updated, as it is sent to the copy() method by ref, but the target obj behave like it is sent by val and all of its updates are ignored outside the method…???

Sould I use 'ref', 'out' key words i nthe method signature etc??

¿Fue útil?

Solución

If you assign to a parameter of a method, for that assignment to be visible to the caller, the parameter must have the ref (or out) modifier. See ref (C# Reference).

Example:

// doesn't do anything!
void Copy(BaseObject target)
{
    ...
    target = Something;
}

// with ref, assignment is to the *same* variable as the caller gave
void Copy(ref BaseObject target)
{
    ...
    target = Something;
}

ADDITION:

As the link I provided notes:

Do not confuse the concept of passing by reference with the concept of reference types

These two concepts are "orthogonal", as the following table illustrates:

                                            |                   |
                                            | ByVal (neither    |  ByRef (ref or
                                            | ref nor out):     |  out keyword):
                                            |                   |
--------------------------------------------+-------------------+----------------------
value type (struct, enum)                   | entire object     |  no copy, argument
                                            | is COPIED         |  must be a variable,
                                            |                   |  same variable used
--------------------------------------------+-------------------+----------------------
reference type (class, interface, delegate) | reference COPIED; |  no copy, argument
                                            | NEW reference to  |  must be a variable,
                                            | same object       |  same variable used
--------------------------------------------+-------------------+----------------------

If you don't use mutable structs, then variables of struct type can only ever change through re-assignemnt, and then the following rule-of-thumb is useful for both value types and reference types:

You need the ref (or out) keyword if and only if your method assigns (including compund assignment like +=) to the parameter in question.

See also What is the use of “ref” for reference-type variables in C#?.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top