8

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

public ArrayList SpillageRiskDescriptions
        {
            get
            {
                return _SpillageRiskDescriptions;
            }
            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?)

4

6 回答 6

13

从技术上讲,它总是按值计算,但您必须了解传递的内容。由于它是引用类型,因此您将引用传回(但按值)。

希望这是有道理的。您总是按值传回结果,但如果类型是引用,则按值传回引用,这意味着您可以更改对象,但不能更改它引用的对象。

于 2011-03-11T15:28:34.713 回答
9

其他答案正确回答了您的主要问题:引用类型属性的是对引用类型实例的引用。

更大的问题是“现在你怎么办?” 大概您希望可以获取列表的代码能够更改它。

这里有几个选项。

首先,无论您做什么,我都建议您立即停止使用 ArrayList 并开始使用更现代、更安全的类型来存储事物列表。List<string>立刻浮现在脑海。

其次,属性的设置者是否有必要公开?您是否希望任何人都能够更改该列表?或者类型本身是否应该负责以某种方式更新它?我会考虑将二传手设为私有。

第三,对于“平凡”的属性,我们有一个更紧凑的语法。你可能会说

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

编译器将为您生成支持字段。

请注意,List<string>仍然允许突变。

如果所有客户关心的是能够一次遍历列表中的一件事,那么您可以这样做:

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

现在调用者不可能改变列表,因为你给他们的只是一个迭代器,而不是访问列表本身。

或者你可以这样做:

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

现在调用者有一个列表的只读视图,如果他们试图修改它,就会抛出异常。

于 2011-03-11T15:51:29.310 回答
2

C# 通过引用返回对象。

只有不按值返回的东西是:

原始类型。
结构类型。
枚举。

于 2011-03-11T15:27:05.420 回答
1

它与它本身是否是财产无关;它是属性的数据类型。在这种情况下,您使用ArrayList的是通过引用传递的类。如果属性被键入为 an int,它将按值传递。

于 2011-03-11T15:26:47.230 回答
0

一个属性实际上是一对两个方法——一个setter和一个getter。它们按原样传递支持字段(或用作源/目标的任何内容)的值。因此,对于引用类型,引用被传递,而对于值类型,值被传递。

// 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;
}

请注意,通过将ArrayList实例分配到您的属性中,您基本上替换ArrayList了支持字段指向的实例。

要回答您的特定问题:

因此,我认为属性返回对原始变量的引用而不是按传递它是否正确?

不,通过使用 getter,您不会获得对该_SpillageRiskDescriptions字段的引用。您将获得字段的,该字段是对(动态分配的)ArrayList实例的引用。

这是因为ArrayList是引用类型吗?

是的,ArrayList是引用类型,因此您会收到对特定ArrayList实例的引用。

int(例如?)也会发生同样的情况

是和不是。的,您将收到一个int字段的值。no ,是一种值类型,因此int如果您修改该值而不显式设置它,则基础字段不会受到影响。

于 2011-03-11T15:28:12.747 回答
0

它与财产没有任何关系。

在这种情况下,您将按值传递对数组列表的引用。

如果你做类似的事情

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

那么对数组列表的引用将被修改。

如果你要做类似的事情

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

那么对数组列表的原始引用根本不会改变。

但是,如果您要通过引用传递引用,例如:

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

那么您的财产最终会得到一个包含单个项目的新数组列表。

于 2011-03-11T15:35:20.540 回答