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

发布于 2024-07-15 08:47:36 字数 518 浏览 4 评论 0原文

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

一旦我知道

  • 我不会将我的类与“仅适用的技术”一起使用在属性上”,
  • 我不会在 getter/setter 中使用验证代码。

是否有任何区别(除了样式/未来开发的区别),例如设置属性时的某种类型的控制?

之间是否有任何其他区别:

public string MyString { get; set; }

public string myString;

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

I realize that it seems to be a duplicate of What is the difference between a Field and a Property in C#? but my question has a slight difference (from my point of view):

Once I know that

  • I will not use my class with "techniques that only works on properties" and
  • I will not use validation code in the getter/setter.

Is there any difference (except the style/future development ones), like some type of control in setting the property?

Is there any additional difference between:

public string MyString { get; set; }

and

public string myString;

(I am aware that, that the first version requires C# 3.0 or above and that the compiler does create the private fields.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

三生殊途 2024-07-22 08:47:36

字段和属性看起来相同,但其实不然。 属性是方法,因此属性不支持某些事情,而属性可能会发生一些事情,但字段的情况下不会发生。

以下是差异列表:

  • 字段可以用作 out/ref 参数的输入。 属性不能。
  • 多次调用时,一个字段总是会产生相同的结果(如果我们忽略多线程的问题)。 DateTime.Now 等属性并不总是等于其自身。
  • 属性可能会抛出异常 - 字段永远不会这样做。
  • 属性可能会产生副作用或需要很长时间才能执行。 字段没有副作用,并且始终与给定类型的预期速度一样快。
  • 属性支持 getters/setters 的不同可访问性 - 字段不支持(但字段可以设置为只读)
  • 使用反射时,属性和字段被视为不同的 MemberTypes,因此它们可以被定位不同(例如,GetFieldsGetProperties
  • 与字段访问相比,JIT 编译器处理属性访问的方式可能非常不同。 然而,它可能会编译为相同的本机代码,但差异的范围是存在的。

Fields and properties look the same, but they are not. Properties are methods and as such there are certain things that are not supported for properties, and some things that may happen with properties but never in the case of fields.

Here's a list of differences:

  • Fields can be used as input to out/ref arguments. Properties can not.
  • A field will always yield the same result when called multiple times (if we leave out issues with multiple threads). A property such as DateTime.Now is not always equal to itself.
  • Properties may throw exceptions - fields will never do that.
  • Properties may have side effects or take a really long time to execute. Fields have no side effects and will always be as fast as can be expected for the given type.
  • Properties support different accessibility for getters/setters - fields do not (but fields can be made readonly)
  • When using reflection the properties and fields are treated as different MemberTypes so they are located differently (GetFields vs GetProperties for example)
  • The JIT Compiler may treat property access very differently compared to field access. It may however compile down to identical native code but the scope for difference is there.
谁许谁一生繁华 2024-07-22 08:47:36

封装。

在第二个实例中,您刚刚定义了一个变量,在第一个实例中,变量周围有一个 getter/setter。 因此,如果您决定稍后验证该变量 - 这会容易得多。

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

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

Encapsulation.

In the second instance you've just defined a variable, in the first, there is a getter / setter around the variable. So if you decide you want to validate the variable at a later date - it will be a lot easier.

Plus they show up differently in Intellisense :)

Edit: Update for OPs updated question - if you want to ignore the other suggestions here, the other reason is that it's simply not good OO design. And if you don't have a very good reason for doing it, always choose a property over a public variable / field.

瀟灑尐姊 2024-07-22 08:47:36

几个快速、明显的差异

  1. 属性可以有访问器关键字。

    public string MyString { get;   私人套装;   } 
      
  2. 属性可以在后代中被覆盖。

    公共虚拟字符串 MyString { get;   受保护集;   } 
      

A couple quick, obvious differences

  1. A property can have accessor keywords.

    public string MyString { get; private set; }
    
  2. A property can be overridden in descendents.

    public virtual string MyString { get; protected set; }
    
够钟 2024-07-22 08:47:36

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

The fundamental difference is that a field is a position in memory where data of the specified type is stored. A property represents one or two units of code that are executed to retrieve or set a value of the specified type. The use of these accessor methods is syntactically hidden by using a member that appears to behave like a field (in that it can appear on either side of an assignment operation).

窝囊感情。 2024-07-22 08:47:36

访问器不仅仅是字段。 其他人已经指出了几个重要的区别,我将再补充一个。

属性参与接口类。 例如:

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。

但我们可以进一步推动设计。 例如,接口可能不处理设置器。 可以说,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);
}

在此代码中,消费者不知道属性设置器 - 了解它不是他的事。 Consumer只需要getters,他从接口,即从合约中获取getters。

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

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

在此代码示例中,消费者再次不知道填充属性。 Consumer 只处理 getters,而具体的实现(以及其背后的业务逻辑,例如测试 name 是否为空)则留给专门的类 - 构建器和工厂。 所有这些操作在现场都是完全不可能的。

Accessors are more than fields. Others have already pointed out several important differences, and I'm going to add one more.

Properties take part in interface classes. For example:

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

This interface can be satisfied in several ways. For example:

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

In this implementation we are protecting both the Person class from getting into an invalid state, as well as the caller from getting null out from the unassigned property.

But we could push the design even further. For example, interface might not deal with the setter. It is quite legitimate to say that consumers of IPerson interface are only interested in getting the property, not in setting it:

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

Previous implementation of the Person class satisfies this interface. The fact that it lets the caller also set the properties is meaningless from the point of view of consumers (who consume IPerson). Additional functionality of the concrete implementation is taken into consideration by, for example, builder:

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

In this code, consumer doesn't know about property setters - it is not his business to know about it. Consumer only needs getters, and he gets getters from the interface, i.e. from the contract.

Another completely valid implementation of IPerson would be an immutable person class and a corresponding person factory:

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

In this code sample consumer once again has no knowledge of filling the properties. Consumer only deals with getters and concrete implementation (and business logic behind it, like testing if name is empty) is left to the specialized classes - builders and factories. All these operations are utterly impossible with fields.

飘逸的'云 2024-07-22 08:47:36

第一个:

public string MyString {get; set; }

是属性; 第二个 (public string MyString) 表示一个字段。

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

The first one:

public string MyString {get; set; }

is a property; the second one ( public string MyString ) denotes a field.

The difference is, that certain techniques (ASP.NET databinding for instances), only works on properties, and not on fields.
The same is true for XML Serialization: only properties are serialized, fields are not serialized.

单身情人 2024-07-22 08:47:36

在许多情况下,属性和字段可能看起来相似,但事实并非如此。 字段所不存在的属性存在一些限制,反之亦然。

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

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

Properties and Fields may, in many cases, seem similar, but they are not. There are limitations to properties that do not exist for fields, and vice versa.

As others have mentioned. You can make a property read-only or write-only by making it's accessor private. You can't do that with a field. Properties can also be virtual, while fields cannot.

Think of properties as syntactic sugar for getXXX()/setXXX() functions. This is how they are implemented behind the scenes.

一个人练习一个人 2024-07-22 08:47:36

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

使用 WPF 时,只能绑定到公共属性。 绑定到公共字段将不起作用。 即使没有实现 INotifyPropertyChanged 也是如此(即使您总是应该这样做)。

There is one other important difference between fields and properties.

When using WPF, you can only bind to public properties. Binding to a public field will not work. This is true even when not implementing INotifyPropertyChanged (even though you always should).

我很坚强 2024-07-22 08:47:36

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

例如,假设您有一个如下所示的 OnChange property

public Action OnChange { get; set; }

如果您想使用委托,则需要更改它OnChangefield 如下:

public event Action OnChange = delegate {};

在这种情况下,我们保护我们的字段免受不必要的访问或修改。

Among other answers and examples, I think this example is useful in some situations.

For example let say you have a OnChange property like following:

public Action OnChange { get; set; }

If you want to use delegates than you need to change it OnChange to field like this:

public event Action OnChange = delegate {};

In such situation we protect our field from unwanted access or modification.

鼻尖触碰 2024-07-22 08:47:36

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

You should always use properties instead of fields for any public fields.This ensures that your library
has the ability to implement encapsulation for any field if required in future without breaking the existing codes.If you replace the fields with properties in existing libraries then all the dependent modules using your library also need to be rebuilt.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文