首页 > 解决方案 > 允许类外部的字段访问是一种好习惯吗?或者应该始终只允许通过属性从外部访问字段?

问题描述

我正在尝试了解 Field 的正确用法以及是否应允许其他类访问该字段还是应该始终通过属性访问该字段?

考虑我有如下代码:

internal class MyCalculator : IDisposable
    {
        public Type1 type1;
        public MyCalculator(Type1 type1)
        {
           this.type = type1;
        }
    }

internal class Accessor
{
   public void Foo()
   {
     MyCalculator obj = new MyCalculator();
     obj.type1.Id = 10;
   }
}

这是允许访问另一个类之外的公共字段的好习惯,还是应该始终只通过属性?

当我检查 List 的源代码时,我看到了这个:

public class List<T> : IList<T>, System.Collections.IList, IReadOnlyList<T>
    {
        private const int _defaultCapacity = 4;

        private T[] _items;
        [ContractPublicPropertyName("Count")]
        private int _size;
        private int _version;
    }

私有属性下划线标记,而相同的字典私有成员没有用下划线标记,如下所示:

public class Dictionary<TKey,TValue>: IDictionary<TKey,TValue>, IDictionary, IReadOnlyDictionary<TKey, TValue>, ISerializable, IDeserializationCallback  {

        private struct Entry {
            public int hashCode;    // Lower 31 bits of hash code, -1 if unused
            public int next;        // Index of next entry, -1 if last
            public TKey key;           // Key of entry
            public TValue value;         // Value of entry
        }

        private int[] buckets;
        private Entry[] entries;
        private int count;
        private int version;
        private int freeList;
        private int freeCount;
}

所以我有点困惑上面2个即列表和字典私人成员之间有什么区别,或者我可能遗漏了什么?

这并不完全是重复的,因为我问了太多事情,当然我可以在问题中提到这一点,但因为我不希望我的标题问题太大。

此外,我在我的代码(字段和属性代码片段)中显示的内容以及在我的特定场景中是否是一个好习惯的上下文中问这个问题。

标签: c#

解决方案


据此:_

有时您可以使用非私有字段,因为无论出于何种原因,您都不关心上述兼容性原因。但是,即使在微不足道的情况下使用属性仍然有好处:

- 有更细粒度的属性访问控制。需要它是公开可获取的,但真的只希望它具有受保护的访问权限吗?没问题(至少从 C# 2 开始)。

- 想要在值更改时闯入调试器?只需在设置器中添加一个断点。

- 想要记录所有访问?只需将日志记录添加到 getter 即可。属性用于数据绑定;字段不是。

在几乎所有情况下,字段都应该是私有的。不仅是非公开的,而且是私人的。使用 C# 3 中的自动属性,基本上没有可读性成本或使用属性而不是字段所涉及的代码量。偶尔您可能会找到一个真正好的理由,但在做出该选择之前仔细考虑一下,特别是如果您将其暴露在内部访问之外。

对于下划线:

没有语言定义的含义 - 它只是一些人用来区分实例变量和局部变量的约定。其他变体包括 m_foo(和 s_foo 或 g_foo 或静态变量)或 mFoo;或者,有些人喜欢给局部变量(和参数)加上前缀而不是实例变量。

只是当你想在类中创建一个变量时,在它前面放一个简单的 {set;get;} 。没有造成伤害。

public int a {set; get;}

推荐阅读