首页 文章

C#3.0中属性和字段的区别

提问于
浏览
132

我意识到它似乎是What is the difference between a Field and a Property in C#?的副本,但我的问题有一点点差异(从我的观点来看):

一旦我知道了

  • 我不会用"techniques that only works on properties"和我的 class

  • 我不会在getter / setter中使用验证码 .

是否有任何区别(风格/未来发展除外),如设置属性时的某种控制类型?

之间有什么额外的区别:

public string MyString { get; set; }

public string myString;

(我知道,第一个版本需要C#3.0或更高版本,并且编译器会创建私有字段 . )

10 回答

  • 1

    封装 .

    在第二个实例中,您刚刚定义了一个变量,在第一个实例中,变量周围有一个getter / setter . 因此,如果您决定在以后验证变量,那么将会更容易 .

    另外它们在Intellisense中的显示方式不同:)

    Edit: 更新OP更新问题 - 如果您想忽略其他建议,另一个原因是它有一个很好的理由, always 选择一个公共变量/字段的属性 .

  • 0

    字段和属性看起来相同,但它们不是 . 属性是方法,因此有些属性不支持某些东西,有些东西可能会在属性中发生,但从不在字段的情况下发生 .

    以下是差异列表:

    • 字段可用作 out/ref 参数的输入 . 属性不能 .

    • 当多次调用时,字段将始终产生相同的结果(如果我们忽略多个线程的问题) . 诸如 DateTime.Now 之类的属性并不总是等于它自己 .

    • 属性可能会抛出异常 - 字段永远不会这样做 .

    • 属性可能有副作用或需要很长时间才能执行 . 字段没有副作用,并且总是与给定类型的预期一样快 .

    • 属性支持getter / setter的不同可访问性 - 字段不支持(但可以使字段为 readonly

    • 使用反射时,属性和字段被视为不同的 MemberTypes ,因此它们的位置不同(例如 GetFields vs GetProperties

    • 与现场访问相比,JIT编译器可以非常不同地处理属性访问 . 然而,它可以编译为相同的本机代码,但差异的范围就在那里 .

  • 10

    几个快速,明显的差异

    • 属性可以具有访问者关键字 .
    public string MyString { get; private set; }
    
    • 可以在后代中覆盖属性 .
    public virtual string MyString { get; protected set; }
    
  • 1

    根本区别在于字段是存储器中存储指定类型数据的位置 . 属性表示一个或两个代码单元,用于检索或设置指定类型的值 . 这些访问器方法的使用在语法上通过使用看起来像字段行为的成员来隐藏(因为它可以出现在赋值操作的任一侧) .

  • 147

    访问者不仅仅是字段 . 其他人已经指出了几个重要的差异,我将再添加一个 .

    属性参与接口类 . 例如:

    interface IPerson
    {
        string FirstName { get; set; }
        string LastName { get; set; }
    }
    

    可以通过多种方式满足该界面 . 例如:

    class Person: IPerson
    {
        private string _name;
        public string FirstName
        {
            get
            {
                return _name ?? string.Empty;
            }
            set
            {
                if (value == null)
                    throw new System.ArgumentNullException("value");
                _name = value;
            }
        }
        ...
    }
    

    在此实现中,我们保护 Person 类不会进入无效状态,以及调用者从未分配属性中获取null .

    但我们可以进一步推动设计 . 例如,接口可能不处理setter . 说 IPerson 接口的消费者只对获取该属性感兴趣,而不是设置它是非常合理的:

    interface IPerson
    {
        string FirstName { get; }
        string LastName { get; }
    }
    

    Person 类的先前实现满足此接口 . 从消费者(使用 IPerson )的角度来看,它让调用者也设置属性这一事实毫无意义 . 例如,构建器会考虑具体实现的其他功能:

    class PersonBuilder: IPersonBuilder
    {
        IPerson BuildPerson(IContext context)
        {
    
            Person person = new Person();
    
            person.FirstName = context.GetFirstName();
            person.LastName = context.GetLastName();
    
            return person;
    
        }
    }
    
    ...
    
    void Consumer(IPersonBuilder builder, IContext context)
    {
        IPerson person = builder.BuildPerson(context);
        Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
    }
    

    在这段代码中,消费者不了解 property 制定者 - 了解它并不是他的事 . 消费者只需要吸气剂,他从界面获得吸气剂,即来自 Contract .

    IPerson 的另一个完全有效的实现是一个不可变的人类和一个相应的人工厂:

    class Person: IPerson
    {
        public Person(string firstName, string lastName)
        {
    
            if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName))
                throw new System.ArgumentException();
    
            this.FirstName = firstName;
            this.LastName = lastName;
    
        }
    
        public string FirstName { get; private set; }
    
        public string LastName { get; private set; }
    
    }
    
    ...
    
    class PersonFactory: IPersonFactory
    {
        public IPerson CreatePerson(string firstName, string lastName)
        {
            return new Person(firstName, lastName);
        }
    }
    ...
    void Consumer(IPersonFactory factory)
    {
        IPerson person = factory.CreatePerson("John", "Doe");
        Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
    }
    

    在此代码示例中,消费者再次不知道填充属性 . 消费者只处理getter和具体实现(以及它背后的业务逻辑,如测试名称是否为空)留给专门的类 - 构建者和工厂 . 使用字段完全不可能完成所有这些操作 .

  • 13

    第一个:

    public string MyString {get; set; }
    

    是一个 property ;第二个( public string MyString )表示一个字段 .

    不同之处在于,某些技术(实例的ASP.NET数据绑定)仅适用于属性,而不适用于字段 . XML序列化也是如此:只有属性是序列化的,而字段则不是序列化 .

  • 40

    在许多情况下,属性和字段似乎相似,但它们不是 . 字段不存在的属性存在限制,反之亦然 .

    正如其他人所说 . 您可以通过将属性设置为私有来使属性成为只读或只写 . 你不能用字段做到这一点 . 属性也可以是虚拟的,而字段则不能 .

    将属性视为getXXX()/ setXXX()函数的语法糖 . 这就是他们在幕后实施的方式 .

  • 7

    字段和属性之间还有另一个重要区别 .

    使用WPF时,只能绑定到公共属性 . 绑定到公共领域将 not 工作 . 即使没有实现 INotifyPropertyChanged (即使你总是应该)也是如此 .

  • 3

    在其他答案和例子中,我认为这个例子在某些情况下很有用 .

    例如,假设你有一个 OnChange property 如下:

    public Action OnChange { get; set; }
    

    如果你想使用代理而不是你需要将它更改为 OnChangefield ,如下所示:

    public event Action OnChange = delegate {};
    

    在这种情况下,我们保护我们的领域免受不必要的访

  • 112

    对于任何公共字段,您应该始终使用属性而不是字段 . 这可以确保您的库能够在不破坏现有代码的情况下为任何字段实现封装 . 如果您使用现有库中的属性替换字段,那么所有使用您的库的依赖模块也需要重建 .

相关问题