开发者

Properties - by value or reference?

I've got the following public property which exposes an Arraylist:

public ArrayList SpillageRiskDescriptions
        {
            get
            {
                return _Sp开发者_高级运维illageRiskDescriptions;
            }
            set
            {
                _SpillageRiskDescriptions = value;
            }
        }

Elsewhere I'm calling

SpillageRiskDescriptions.Add("VENTILATE AREA");
SpillageRiskDescriptions.Add("DO NOT ALLOW SPILLAGE TO ENTER MAINS");

These seem to be adding elements to the private ArrayList _SpillageRiskDescriptions (through the property) whereas I would've expected this to cause a problem. Therefore am I correct in thinking that properties return a reference to the original variable and not passing it by value? Is this because ArrayList is a reference type? Will the same happen with an int (for example?)


Technically it's always by value, but you have to understand what is being passed. Since it's a reference type, you are passing a reference back (but by value).

Hope that makes sense. You always pass the result back by value, but if the type is a reference you are passing the reference back by value, which means you can change the object, but not which object it refers to.


The other answers have correctly answered your primary question: that the value of a property of reference type is a reference to an instance of the reference type.

The larger question is "now what do you do about it?" Presumably you do not want code that can obtain the list to be able to change it.

There are several options here.

First, no matter what you do I recommend that you stop using ArrayList right now and start using a more modern, safe type for storing a list of things. List<string> comes immediately to mind.

Second, is it necessary that the setter of the property be public? Do you want just anyone to be able to change that list? Or should the type itself be responsible for updating it somehow? I'd consider making the setter private.

Third, we have a more compact syntax for a "trivial" property. You could be saying

public List<string> SpillageListDescriptions { get; private set; }

and the compiler will generate the backing field for you.

Note that List<string> still allows mutation.

If all the client cares about is being able to iterate over the list one thing at a time, then you can do this:

private List<string> descriptions = whatever;
public IEnumerable<string> SpillageListDescriptions 
{ 
    get 
    {
        if (descriptions == null) yield break;
        foreach(var description in descriptions) 
            yield return description;
    }
}

and now it is impossible for the caller to mutate the list, because all you're giving them is an iterator over it, not access to the list itself.

Or you could do:

private List<string> descriptions = whatever;
public IList<string> SpillageListDescriptions 
{ 
    get 
    {
        return new ReadOnlyCollection<string>(descriptions); 
    }
}

And now the caller has a read-only view of the list that will throw an exception if they attempt to modify it.


C# returns objects by reference.

Only things that aren't returned by value are:

Primitive types.
Struct types.
Enums.


It has nothing to do with whether it is a property per se; it is the data type of the property. In this case, you are using ArrayList which is a class that is passed by reference. If the property were typed as an int it would be passed by value.


A property is actually a pair of two methods — a setter and a getter. They pass the value of the backing field (or whatever is used as the source / destination) as it is. Hence, for reference types the reference is passed, and for value types the value is passed.

// this is how the getter method looks like
public ArrayList get_SpillageRiskDescriptions()
{
    return _SpillageRiskDescriptions;
}

// this is how the setter method looks like
public void set_SpillageRiskDescriptions(ArrayList value)
{
    _SpillageRiskDescriptions = value;
}

Note that by assigning an ArrayList instance into your property you basically replace the ArrayList instance pointed to by the backing field.

To answer your particular questions:

Therefore am I correct in thinking that properties return a reference to the original variable and not passing it by value?

No, by using the getter you don't get a reference to the _SpillageRiskDescriptions field. You get the value of the field which is a reference to a (dynamically allocated) ArrayList instance.

Is this because ArrayList is a reference type?

Yes, ArrayList is a reference type and thus you receive the reference to the particular ArrayList instance.

Will the same happen with an int (for example?)

Yes and no. Yes, you will receive the value of an int field. And no, int is a value type, so if you modify the value without explicitly setting it back, the underlying field won't be affected.


It doesn't have anything to with the property.

In this case, you are passing a reference to the array list by value.

If you do something like

      void AddSomethingToArrayList(ArrayList spillageRiskDescriptions){
           spillageRiskDescriptions.Add("Something");
      }

then the reference to the array list will be modified.

If you were to do something like

      void ReassignArrayList(ArrayList spillageRiskDescriptions){
           spillageRiskDescriptions = new ArrayList();
           spillageRiskDescriptions.Add("Something");
      }

then the original reference to the array list would not be changed at all.

But if you were to pass the reference by reference such as in:

      void ReassignArrayListByRef(ref ArrayList spillageRiskDescriptions){
           spillageRiskDescriptions = new ArrayList();
           spillageRiskDescriptions.Add("Something");
      }

then your property would end up with a new array list with a single item.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜