为什么我应该避免在 C# 中使用属性?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/694711/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 13:46:34  来源:igfitidea点击:

Why should I avoid using Properties in C#?

c#properties

提问by Quan Mai

In his excellent book, CLR Via C#, Jeffrey Richter said that he doesn't like properties, and recommends not to use them. He gave some reason, but I don't really understand. Can anyone explain to me why I should or should not use properties? In C# 3.0, with automatic properties, does this change?

Jeffrey Richter 在他的优秀著作 CLR Via C# 中说他不喜欢属性,并建议不要使用它们。他给出了一些理由,但我真的不明白。谁能向我解释为什么我应该或不应该使用属性?在 C# 3.0 中,使用自动属性,这会改变吗?

As a reference, I added Jeffrey Richter's opinions:

作为参考,我补充了 Jeffrey Richter 的意见:

? A property may be read-only or write-only; field access is always readable and writable. If you define a property, it is best to offer both get and set accessor methods.

? 属性可以是只读的或只写的;字段访问始终是可读和可写的。如果定义属性,最好同时提供 get 和 set 访问器方法。

? A property method may throw an exception; field access never throws an exception.

? 属性方法可能会抛出异常;字段访问永远不会抛出异常。

? A property cannot be passed as an out or ref parameter to a method; a field can. For example, the following code will not compile:

? 属性不能作为 out 或 ref 参数传递给方法;一个字段可以。例如,以下代码将无法编译:

using System;
public sealed class SomeType
{
   private static String Name 
   {
     get { return null; }
     set {}
   }
   static void MethodWithOutParam(out String n) { n = null; }
   public static void Main()
   {
      // For the line of code below, the C# compiler emits the following:
      // error CS0206: A property or indexer may not
      // be passed as an out or ref parameter
      MethodWithOutParam(out Name);
   }
}

? A property method can take a long time to execute; field access always completes immediately. A common reason to use properties is to perform thread synchronization, which can stop the thread forever, and therefore, a property should not be used if thread synchronization is required. In that situation, a method is preferred. Also, if your class can be accessed remotely (for example, your class is derived from System.MashalByRefObject), calling the property method will be very slow, and therefore, a method is preferred to a property. In my opinion, classes derived from MarshalByRefObject should never use properties.

? 一个属性方法可能需要很长时间才能执行;现场访问总是立即完成。使用属性的一个常见原因是执行线程同步,这可以永远停止线程,因此,如果需要线程同步,则不应使用属性。在这种情况下,首选一种方法。此外,如果您的类可以远程访问(例如,您的类是从 System.MashalByRefObject 派生的),则调用属性方法将非常慢,因此,方法优先于属性。在我看来,从 MarshalByRefObject 派生的类不应该使用属性。

? If called multiple times in a row, a property method may return a different value each time; a field returns the same value each time. The System.DateTime class has a readonly Now property that returns the current date and time. Each time you query this property, it will return a different value. This is a mistake, and Microsoft wishes that they could fix the class by making Now a method instead of a property.

? 如果连续多次调用,一个属性方法可能每次都返回不同的值;一个字段每次返回相同的值。System.DateTime 类具有返回当前日期和时间的只读 Now 属性。每次查询此属性时,它都会返回不同的值。这是一个错误,微软希望他们可以通过使 Now 成为一个方法而不是一个属性来修复这个类。

? A property method may cause observable side effects; field access never does. In other words, a user of a type should be able to set various properties defined by a type in any order he or she chooses without noticing any different behavior in the type.

? 一个属性方法可能会导致可观察到的副作用;现场访问从来没有。换句话说,一个类型的用户应该能够以他或她选择的任何顺序设置由一个类型定义的各种属性,而不会注意到该类型中的任何不同行为。

? A property method may require additional memory or return a reference to something that is not actually part of the object's state, so modifying the returned object has no effect on the original object; querying a field always returns a reference to an object that is guaranteed to be part of the original object's state. Working with a property that returns a copy can be very confusing to developers, and this characteristic is frequently not documented.

? 一个属性方法可能需要额外的内存,或者返回对实际上不属于对象状态的某些东西的引用,因此修改返回的对象对原始对象没有影响;查询一个字段总是返回一个对象的引用,该对象保证是原始对象状态的一部分。使用返回副本的属性可能会让开发人员感到非常困惑,而且这个特性通常没有记录。

采纳答案by Jon Skeet

Jeff's reason for disliking properties is because they look like fields - so developers who don't understand the difference will treat them as if they're fields, assuming that they'll be cheap to execute etc.

Jeff 不喜欢属性的原因是因为它们看起来像字段 - 所以不了解差异的开发人员会将它们视为字段,假设它们执行起来很便宜等等。

Personally I disagree with him on this particular point - I find properties make the client code much simpler to read than the equivalent method calls. I agree that developers need to know that properties are basically methods in disguise - but I think that educating developers about that is better than making code harder to read using methods. (In particular, having seen Java code with several getters and setters being called in the same statement, I know that the equivalent C# code would be a lot simpler to read. The Law of Demeter is all very well in theory, but sometimes foo.Name.Lengthreally is the right thing to use...)

我个人在这一点上不同意他的观点 - 我发现属性使客户端代码比等效的方法调用更易于阅读。我同意开发人员需要知道属性基本上是伪装的方法 - 但我认为对开发人员进行这方面的教育比使用方法使代码更难阅读更好。(特别是,看过在同一个语句中调用多个 getter 和 setter 的 Java 代码后,我知道等效的 C# 代码会更容易阅读。德米特定律在理论上非常好,但有时foo.Name.Length确实如此正确使用...)

(And no, automatically implemented properties don't really change any of this.)

(不,自动实现的属性并没有真正改变任何这些。)

This is slightly like the arguments against using extension methods - I can understand the reasoning, but the practical benefit (when used sparingly) outweighs the downside in my view.

这有点像反对使用扩展方法的论点——我可以理解其中的推理,但在我看来,实际的好处(当谨慎使用时)超过了缺点。

回答by Konstantin Tarkus

I don't see any reasons why you shouldn't use Properties in general.

我看不出有任何理由说明您一般不应使用 Properties。

Automatic properties in C# 3+ only simplify syntax a bit (a la syntatic sugar).

C# 3+ 中的自动属性只是稍微简化了语法(一种语法糖)。

回答by Rashack

That reason must have been given within a very specific context. It's usually the other way round - it is recomended to use properties as they give you a level of abstraction enabling you to change behaviour of a class without affecting its clients...

这个原因一定是在非常具体的背景下给出的。它通常是相反的 - 建议使用属性,因为它们为您提供了一个抽象级别,使您能够在不影响其客户端的情况下更改类的行为......

回答by jalf

I haven't read the book, and you haven't quoted the part of it you don't understand, so I'll have to guess.

我没读过这本书,你也没有引用你不明白的部分,所以我不得不猜测。

Some people dislike properties because they can make your code do surprising things.

有些人不喜欢属性,因为它们可以让您的代码做出令人惊讶的事情。

If I type Foo.Bar, people reading it will normally expect that this is simply accessing a member field of the Foo class. It's a cheap, almost free, operation, and it's deterministic. I can call it over and over, and get the same result every time.

如果我输入Foo.Bar,阅读它的人通常会认为这只是访问 Foo 类的成员字段。这是一种廉价的、几乎免费的操作,而且是确定性的。我可以一遍又一遍地调用它,每次都得到相同的结果。

Instead, with properties, it might actually be a function call. It might be an infinite loop. It might open a database connection. It might return different values every time I access it.

相反,对于属性,它实际上可能是一个函数调用。这可能是一个无限循环。它可能会打开一个数据库连接。每次访问它时,它可能会返回不同的值。

It is a similar argument to why Linus hates C++. Your code can act surprising to the reader. He hates operator overloading: a + bdoesn't necessarily mean simple addition. It may mean some hugely complicated operation, just like C# properties. It may have side effects. It may do anything.

这与 Linus 讨厌 C++ 的原因类似。您的代码可能会让读者感到惊讶。他讨厌运算符重载:a + b不一定意味着简单的加法。这可能意味着一些非常复杂的操作,就像 C# 属性一样。它可能有副作用。它可以做任何事情。

Honestly, I think this is a weak argument. Both languages are full of things like this. (Should we avoid operator overloading in C# as well? After all, the same argument can be used there)

老实说,我认为这是一个弱论点。这两种语言都充满了这样的东西。(我们是否也应该避免在 C# 中操作符重载?毕竟,可以在那里使用相同的参数)

Properties allow abstraction. We can pretendthat something is a regular field, and use it as if it was one, and not have to worry about what goes on behind the scenes.

属性允许抽象。我们可以假装某事物是一个常规字段,并把它当作一个字段来使用,而不必担心幕后发生的事情。

That's usually considered a good thing, but it obviously relies on the programmer writing meaningful abstractions. Your properties shouldbehave like fields. They shouldn't have side effects, they shouldn't perform expensive or unsafe operations. We want to be able to think of themas fields.

这通常被认为是一件好事,但它显然依赖于程序员编写有意义的抽象。您的属性应该表现得像字段。它们不应有副作用,不应执行昂贵或不安全的操作。我们希望能够将它们视为字段。

However, I have another reason to find them less than perfect. They can not be passed by reference to other functions.

但是,我还有另一个理由认为它们并不完美。它们不能通过引用传递给其他函数。

Fields can be passed as ref, allowing a called function to access it directly. Functions can be passed as delegates, allowing a called function to access it directly.

字段可以作为 传递ref,允许被调用的函数直接访问它。函数可以作为委托传递,允许被调用的函数直接访问它。

Properties... can't.

属性……不能。

That sucks.

那太糟糕了。

But that doesn't mean properties are evil or shouldn't be used. For many purposes, they're great.

但这并不意味着属性是邪恶的或不应该被使用。出于许多目的,它们很棒。

回答by Steve

Personally I only use properties when creating simple get / set methods. I stray away from it when coming to complicated data structures.

我个人只在创建简单的 get/set 方法时使用属性。在处理复杂的数据结构时,我偏离了它。

回答by M4N

I don't agree with Jeffrey Richter, but I can guess why he doesn't like properties (I haven't read his book).

我不同意 Jeffrey Richter 的观点,但我能猜到他为什么不喜欢房产(我还没有读过他的书)。

Even though, properties are just like methods (implementation-wise), as a user of a class, I expect that its properties behave "more or less" like a public field, e.g:

尽管如此,属性就像方法(实现方面),作为一个类的用户,我希望它的属性“或多或少”表现得像一个公共字段,例如:

  • there's no time-consuming operation going on inside the property getter/setter
  • the property getter has no side effects (calling it multiple times, does not change the result)
  • 在属性 getter/setter 中没有进行耗时的操作
  • 属性 getter 没有副作用(多次调用,不会改变结果)

Unfortunately, I have seen properties which did not behave that way. But the problem are not the properties themselves, but the people who implemented them. So it just requires some education.

不幸的是,我看到过不那么行为的属性。但问题不在于属性本身,而在于实现它们的人。所以它只需要一些教育。

回答by Mark Simpson

It's just one person's opinion. I've read quite a few c# books and I've yet to see anyone else saying "don't use properties".

这只是一个人的意见。我已经阅读了很多 c# 书籍,但我还没有看到其他人说“不要使用属性”。

I personally think properties are one of the best things about c#. They allow you to expose state via whatever mechanism you like. You can lazily instantiate the first time something is used and you can do validation on setting a value etc. When using and writing them, I just think of properties as setters and getters which a much nicer syntax.

我个人认为属性是 C# 最好的东西之一。它们允许您通过您喜欢的任何机制公开状态。您可以在第一次使用某些东西时懒惰地实例化,并且可以对设置值等进行验证。在使用和编写它们时,我只是将属性视为 setter 和 getter,它们的语法要好得多。

As for the caveats with properties, there are a couple. One is probably a misuse of properties, the other can be subtle.

至于属性的警告,有几个。一个可能是对属性的滥用,另一个可能是微妙的。

Firstly, properties are types of methods. It can be surprising if you place complicated logic in a property because most users of a class will expect the property to be fairly lightweight.

首先,属性是方法的类型。如果在属性中放置复杂的逻辑可能会令人惊讶,因为类的大多数用户都希望该属性相当轻量级。

E.g.

例如

public class WorkerUsingMethod
{
   // Explicitly obvious that calculation is being done here
   public int CalculateResult()
   { 
      return ExpensiveLongRunningCalculation();
   }
}

public class WorkerUsingProperty
{
   // Not at all obvious.  Looks like it may just be returning a cached result.
   public int Result
   {
       get { return ExpensiveLongRunningCalculation(); }
   }
}

I find that using methods for these cases helps to make a distinction.

我发现对这些情况使用方法有助于区分。

Secondly, and more importantly, properties can have side-effects if you evaluate them while debugging.

其次,更重要的是,如果在调试时评估属性,属性可能会产生副作用。

Say you have some property like this:

假设你有一些这样的财产:

public int Result 
{ 
   get 
   { 
       m_numberQueries++; 
       return m_result; 
   } 
}

Now suppose you have an exception that occurs when too many queries are made. Guess what happens when you start debugging and rollover the property in the debugger? Bad things. Avoid doing this! Looking at the property changes the state of the program.

现在假设您有一个异常,当进行太多查询时会发生这种异常。猜猜当您开始调试并在调试器中翻转属性时会发生什么?坏事。避免这样做!查看属性会更改程序的状态。

These are the only caveats I have. I think the benefits of properties far outweigh the problems.

这些是我唯一的警告。我认为属性的好处远远大于问题。

回答by Hejazzman

Well, lets take his arguments one by one:

好吧,让我们一一分析他的论点:

A property may be read-only or write-only; field access is always readable and writable.

属性可以是只读的或只写的;字段访问始终是可读和可写的。

This is a win for properties, since you have more fine-grained control of access.

这是属性的胜利,因为您可以更细粒度地控制访问。

A property method may throw an exception; field access never throws an exception.

属性方法可能会抛出异常;字段访问永远不会抛出异常。

While this is mostly true, you can very well call a method on a not initialized object field, and have an exception thrown.

虽然这几乎是正确的,但您可以很好地在未初始化的对象字段上调用方法,并抛出异常。

? A property cannot be passed as an out or ref parameter to a method; a field can.

? 属性不能作为 out 或 ref 参数传递给方法;一个字段可以。

Fair.

公平的。

? A property method can take a long time to execute; field access always completes immediately.

? 一个属性方法可能需要很长时间才能执行;现场访问总是立即完成。

It can also take very little time.

它也可能需要很少的时间。

? If called multiple times in a row, a property method may return a different value each time; a field returns the same value each time.

? 如果连续多次调用,一个属性方法可能每次都返回不同的值;一个字段每次返回相同的值。

Not true. How do you know the field's value has not changed (possibly by another thread)?

不对。你怎么知道字段的值没有改变(可能被另一个线程改变了)?

The System.DateTime class has a readonly Now property that returns the current date and time. Each time you query this property, it will return a different value. This is a mistake, and Microsoft wishes that they could fix the class by making Now a method instead of a property.

System.DateTime 类具有返回当前日期和时间的只读 Now 属性。每次查询此属性时,它都会返回不同的值。这是一个错误,微软希望他们可以通过使 Now 成为一个方法而不是一个属性来修复这个类。

If it is a mistake it's a minor one.

如果它是一个错误,它是一个小错误。

? A property method may cause observable side effects; field access never does. In other words, a user of a type should be able to set various properties defined by a type in any order he or she chooses without noticing any different behavior in the type.

? 一个属性方法可能会导致可观察到的副作用;现场访问从来没有。换句话说,一个类型的用户应该能够以他或她选择的任何顺序设置由一个类型定义的各种属性,而不会注意到该类型中的任何不同行为。

Fair.

公平的。

? A property method may require additional memory or return a reference to something that is not actually part of the object's state, so modifying the returned object has no effect on the original object; querying a field always returns a reference to an object that is guaranteed to be part of the original object's state. Working with a property that returns a copy can be very confusing to developers, and this characteristic is frequently not documented.

? 一个属性方法可能需要额外的内存,或者返回对实际上不属于对象状态的某些东西的引用,因此修改返回的对象对原始对象没有影响;查询一个字段总是返回一个对象的引用,该对象保证是原始对象状态的一部分。使用返回副本的属性可能会让开发人员感到非常困惑,而且这个特性通常没有记录。

Most of the protestations could be said for Java's getters and setters too --and we had them for quite a while without such problems in practice.

大多数抗议也可以说是针对 Java 的 getter 和 setter 的——而且我们使用它们已经有一段时间了,在实践中没有出现此类问题。

I think most of the problems could be solved by better syntax highlighting (i.e differentiating properties from fields) so the programmer knows what to expect.

我认为大多数问题都可以通过更好的语法突出显示(即区分属性和字段)来解决,这样程序员就知道会发生什么。

回答by Cecil Has a Name

I can't help picking on the details of Jeffrey Richter's opinions:

我不禁挑出杰弗里·里希特 (Jeffrey Richter) 意见的细节:

A property may be read-only or write-only; field access is always readable and writable.

属性可以是只读的或只写的;字段访问始终是可读和可写的。

Wrong: Fields can marked read-only so only the object's constructor can write to them.

错误:字段可以标记为只读,因此只有对象的构造函数可以写入它们。

A property method may throw an exception; field access never throws an exception.

属性方法可能会抛出异常;字段访问永远不会抛出异常。

Wrong: The implementation of a class can change the access modifier of a field from public to private. Attempts to read private fields at runtime will always result in an exception.

错误:类的实现可以将字段的访问修饰符从 public 更改为 private。尝试在运行时读取私有字段总是会导致异常。

回答by Steve

There is a time when I consider not using properties, and that is in writing .Net Compact Framework code. The CF JIT compiler does not perform the same optimisation as the desktop JIT compiler and does not optimise simple property accessors, so in this case adding a simple property causes a small amount of code bloat over using a public field. Usually this wouldn't be an issue, but almost always in the Compact Framework world you are up against tight memory constraints, so even tiny savings like this do count.

有一段时间我考虑不使用属性,那就是编写 .Net Compact Framework 代码。CF JIT 编译器不执行与桌面 JIT 编译器相同的优化,也不优化简单的属性访问器,因此在这种情况下,添加一个简单的属性会导致使用公共字段的少量代码膨胀。通常这不会成为问题,但几乎总是在 Compact Framework 世界中,您会遇到严格的内存限制,因此即使像这样的微小节省也很重要。