2011-03-11 69 views
7

我有暴露的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(例如?)

回答

9

从技术上讲,它始终是有价值的,但你必须明白传递的是什么。由于它是一个引用类型,所以你传递了一个引用(但是通过值)。

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

+2

想象它与C++一样,你可以将一个指针传递给一个对象,并且你可以改变那个指针指向的内容,但是你不能指向其他东西,因为你有一个指针的副本而不是原始指针。如果你想改变它指向的对象,你必须传递一个指针指向一个指针(或者指向一个指针)。这就是为什么在C#中,如果要更改引用的对象,则需要ref和out关键字。 – 2011-03-11 15:31:51

+0

非常好 - 这非常有用 – 2011-03-11 15:35:27

1

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

2

C#通过引用返回对象。

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

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

+0

本质上是真实的,尽管从技术上讲,它通过值传回对象引用。 – 2011-03-11 15:33:54

+0

另外C++指针是按值传递的,但是这是通过引用定义的。传递对象的地址而不是对象本身。 – 2011-03-11 16:15:15

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实例的引用。

同样会发生int(例如?)

是和否。 是的,您将收到一个int字段的值。并且,int是一个值类型,所以如果您修改该值而不明确地将其设置回来,则基础字段将不受影响。

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

那么你的财产将结束与一个单一的项目一个新的数组列表。

7

其他的答案都正确地回答了你的首要问题:是引用类型的属性参考的引用类型的实例

更大的问题是“现在你对此做了什么?想必你不是想要的代码,可以获得该清单能够更改它。

这里有几个选项。

首先,不管你做什么,我建议你现在停止使用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); 
    } 
} 

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

+0

非常感谢您的反馈,但是其中大部分内容(短属性语法和带有公共getter的私有setter)仅在框架的更高版本中可用 - 我正在使用.NET2。我实际访问的原因是,我可以将ArrayList转换为列表。然而,它很好找出我在做什么是对的。 – 2011-03-11 16:01:22

+0

他提到的唯一解决方案在.Net 2中不可用,它是自动属性,可以在.Net 2中手工实现。你还需要用'string'替换'var'。 – Brian 2011-03-14 13:16:50

相关问题