当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《C#3.0+中属性和字段的区别》经验,为你挑选了6个好方法。

我意识到它似乎是C#中字段和属性之间有什么区别的重复?但我的问题略有不同(从我的观点来看):

一旦我知道了

我不会将我的课程用于"仅适用于属性的技术"和

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

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

是否有任何额外的区别:

public string MyString { get; set; }

public string myString;

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



1> Brian Rasmus..:

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

这是一个差异列表:

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

多次调用时,字段总是会产生相同的结果(如果我们忽略了多个线程的问题).诸如DateTime.Now并不总是等于自身的财产.

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

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

属性支持getter/setter的不同可访问性 - 字段不支持(但可以创建字段readonly)

当使用反射的属性和字段将被视为不同的MemberTypes,以便它们位于不同的(GetFieldsVS GetProperties例如)

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


@Noldorin:我同意,但遗憾的是***应该是这里的关键字.对于保证行为的字段.我不是说你应该使用字段,但重要的是要注意语义差异.
但请注意,如果采用良好做法,其中一些要点不应该是差异.也就是说,属性真的不应该有副作用,也不应该花费很长时间来执行.
是的,公平的.不幸的是,初学者程序员经常对这些事情一无所知......
我觉得这个答案比接受的答案更好.我开始认为,总是喜欢属性而不是字段的"可接受"方式是糟糕的思考.如果您只需要处理数据,请使用字段.如果需要将功能应用于数据,请使用方法.由于属性可能有副作用,你不知道(特别是如果你没有设计库并且几乎没有文档),在大多数情况下它们似乎与我相反.
此外,字段可能具有字段初始值设定项,而属性必须在构造函数中初始化.

2> Mark Ingram..:

封装.

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

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

编辑: OP更新更新问题 - 如果你想忽略其他建议,另一个原因是它不是好的OO设计.如果您没有充分理由这样做,请始终在公共变量/字段上选择一个属性.


@Serge - 它会影响已编译的代码.例如,如果您正在开发由多个应用程序使用的库,则将字段更改为该库中的属性将需要重新编译每个应用程序.如果它是一个属性,您可以毫无顾虑地更新该属性.
如果消费代码总是与受影响的类同时重新编译(所以任何私有或内部没有内部可见的是100%安全),那么将它作为一个字段就完全可以了
为什么会更容易?是什么阻止我将字段转换为属性并添加私有支持字段?这对调用代码有何影响?

3> Dustin Campb..:

几个快速,明显的差异

    属性可以具有访问者关键字.

    public string MyString { get; private set; }
    

    在后代可以覆盖财产.

    public virtual string MyString { get; protected set; }
    



4> AnthonyWJone..:

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



5> Zoran Horvat..:

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

属性参与接口类.例如:

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

在这段代码中,消费者并不了解财产制定者 - 了解它并不是他的事.消费者只需要吸气剂,他从界面获得吸气剂,即从合同中获取.

另一个完全有效的实现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和具体实现(以及它背后的业务逻辑,如测试名称是否为空)留给专门的类 - 构建器和工厂.所有这些操作完全不可能用于字段.



6> Frederik Ghe..:

第一个:

public string MyString {get; set; }

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

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


错误.XML序列化可以序列化公共字段.
也许.但是,当您从类创建对象数据源时,您只能使用属性,而不是字段.(除非我做错了什么:P)
推荐阅读
牛尾巴2010
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有