【问题标题】:Properties - by value or reference?属性 - 按值或参考?
【发布时间】:2011-07-13 14:00:43
【问题描述】:

我有以下公开 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 添加元素(通过属性),而我预计这会导致问题。因此,我认为属性将 reference 返回到原始变量而不是通过 value 传递它是否正确?这是因为ArrayList 是引用类型吗? int 也会发生同样的情况(例如?)

【问题讨论】:

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


    【解决方案1】:

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

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

    【讨论】:

    • 把它想象成C++,你可以传递一个指向一个对象的指针,你可以改变这个指针指向的东西,但是你不能让它指向别的东西,因为你有一个指针而不是原始指针。如果要更改它指向的对象,则必须将指针传递给指针(或对指针的引用)。这就是为什么在 C# 中如果要更改所引用的对象,则需要 ref 和 out 关键字。
    • 优秀 - 这很有意义
    【解决方案2】:

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

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

    这里有几个选项。

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

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

    第三,我们为“琐碎”属性提供了更紧凑的语法。你可能会说

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

    编译器会为你生成支持字段。

    请注意,List&lt;string&gt; 仍然允许突变。

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

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

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

    【讨论】:

    • 非常感谢您的反馈,但是其中大多数(短属性语法和带有公共 getter 的私有 setter)仅在框架的更高版本中可用 - 我使用的是 .NET2。我实际访问它的全部原因是我可以将 ArrayList 转换为 List。但是很高兴知道我在做什么是对的。
    • 他提到的唯一在 .Net 2 中不可用的解决方案是自动属性,可以在 .Net 2 中手动轻松实现。您还需要将var 替换为string
    【解决方案3】:

    C# 通过引用返回对象。

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

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

    【讨论】:

    • 本质上是正确的,尽管从技术上讲,它通过值传递回对象引用。
    • c++ 指针也是按值传回的,但这是按引用的定义。传递的是对象的地址,而不是对象本身。
    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      一个属性实际上是一对两个方法——一个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 字段的值。而noint 是一个值类型,所以如果你修改了值而没有显式地把它设置回来,底层的字段不会受到影响。

      【讨论】:

        【解决方案6】:

        它与属性没有任何关系。

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

        如果你做类似的事情

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-04-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-08-10
          相关资源
          最近更新 更多