属性 - 按值或参考?

时间:2011-03-11 15:22:25

标签: c# .net properties pass-by-reference pass-by-value

我有以下显示Arraylist的公共财产:

public ArrayList SpillageRiskDescriptions
        {
            get
            {
                return _SpillageRiskDescriptions;
            }
            set
            {
                _SpillageRiskDescriptions = value;
            }
        }

在其他地方,我正在打电话

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

这些似乎是将元素添加到私有ArrayList _SpillageRiskDescriptions(通过属性),而我希望这会导致问题。因此,我认为属性会将引用返回到原始变量而不是通过传递它是否正确?这是因为ArrayList是引用类型吗?使用int(例如?)

会发生同样的情况

6 个答案:

答案 0 :(得分:11)

从技术上讲,它总是按价值计算,但你必须了解传递的内容。因为它是一个引用类型,所以你传回一个引用(但是按值)。

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

答案 1 :(得分:8)

其他答案已正确回答了您的主要问题:参考类型属性的引用引用类型的实例

更大的问题是“现在你怎么办?”据推测,您想要获取列表的代码能够更改

这里有几种选择。

首先,无论你做什么我建议你立即停止使用ArrayList并开始使用更现代,安全的类型来存储事物列表。我会立刻想到List<string>

其次,该属性的 setter 是否必须公开?你想让任何人都能改变这个清单吗?或者类型本身是否应该以某种方式更新它?我会考虑将setter设为私有。

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

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

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

答案 2 :(得分:2)

C#通过引用返回对象。

只有未按价值返回的内容为:

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

答案 3 :(得分:1)

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

答案 4 :(得分: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字段的值。并且没有int是一种值类型,因此如果您在未明确设置值的情况下修改该值,则基础字段不会受到影响。

答案 5 :(得分: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");
      }

然后你的属性最终会得到一个包含单个项目的新数组列表。