简体   繁体   English

在C#中,有什么更好的替代方法来使用getter和setter?

[英]What are better alternatives to getters and setters in C#?

I have read some about the use of getters/setters in object oriented programming and many resources such as this suggest that they should be used very infrequently. 我看过一些关于面向对象编程和很多资源,如使用getter / setter方法的这个建议,他们应该是非常不经常使用。 A quote from that article says: 该文章的引言说:

Don't ask for the information you need to do the work; 不要要求您进行工作所需的信息; ask the object that has the information to do the work for you. 询问具有该信息的对象为您完成工作。

While that sounds good in principle, I'm not particularly sure how that is best implemented. 虽然这在原则上听起来不错,但我不确定如何最好地实现这一点。 Say taht I have a class the describes a car. 说我有一堂课描述一辆汽车。 Inside that class, lets say that the brand of this car stored in the class is "Toyota". 在该类别中,可以说该类别中存储的这款汽车的品牌是“丰田”。 Now I have a GUI that wants to display that this is a "Toyota". 现在,我有一个GUI,它想要显示这是“丰田”。 How does one do that without a getter? 没有吸气剂怎么办?

Even if I abstract out that the "Toyota" is stored as a String and return a TextBox with "Toyota" already written in it, this sounds, at best, like a getter of a wrapped form of the original property. 即使我抽象出“ Toyota”作为字符串存储并返回一个文本框,其中已写有“ Toyota”,但这听起来充其量不过是原始属性的包装形式的获取器。 I just thought that things like TextBoxes should be only in the GUI's class, and not in helper classes like my car class here. 我只是认为诸如TextBoxes之类的东西应该只在GUI的类中,而不应该在我的car类之类的帮助器类中。

That article is describing that you should use methods instead of property getters/setters. 该文章描述了您应该使用方法而不是属性获取器/设置器。 Basically it's suggesting a method should perform an action to modify state instead of allowing a setter to modify state. 基本上,这建议一种方法应执行操作来修改状态,而不是允许设置器修改状态。 eg I could have a class with a Month and a Day property. 例如,我可以开设一个带有“月和日”属性的课程。 I could then have code that does this: 然后,我可以有执行此操作的代码:

obj.Day = 28;
obj.Month = Months.February;
obj.Day = 30;
obj.Month = Months.March;

As soon as I set a day to 30 while month is February, I have invalid state. 一旦我将日期设置为30,而月份为2月,则状态为无效。

The article suggest that a class shouldn't allow this type of thing but provide specific methods to perform specific actions, like: 文章建议类不应允许此类事情,而应提供执行特定操作的特定方法,例如:

obj.ChangeDate(Months.March, 30);

If a date time analogy is confusing due to DateTime, you could have a similar example with lat/long coords: 如果由于DateTime而使日期时间类比令人困惑,则可以使用经纬度坐标类似的示例:

obj.Latitude = 45.4112;
obj.Longitude = -75.6981;
//... 
obj.Latitude = 39.73;
obj.Longitude = -86.27;

When Latitude is set to 39.73 the location becomes a place near Newark instead of Ottawa (the first lat/long) or Indianapolis (the second lat/long). 当“纬度”设置为39.73时,该位置将成为Newark附近的位置,而不是渥太华(第一纬度/经度)或印第安纳波利斯(第二纬度/经度)。 Leaving settings for lat/long leaves the interface open to not being able to verify its invariants and some may say not truly object-oriented. 保留纬度/经度的设置会使接口处于无法验证其不变性的开放状态,并且有些人可能说不是真正面向对象的。 So, you might have a method instead: 因此,您可能有一个方法代替:

obj.MoveTo(39.73, -86.27);

OO implies both encapsulated state and behaviour. OO意味着封装状态和行为。 While some may thing that properties "encapsulate" state, they normally don't. 尽管某些属性可能会“封装”状态,但通常不会。 They decouple implementation from the interface so that what is used as a backing store for the properties can change--but, it rarely ever does; 它们将实现与接口分离开来,以便可以更改用作属性的后备存储的东西,但是很少这样做。 so the properties are simply making available implementation details differently than providing public fields. 因此,这些属性只是在提供实现细节方面与提供公共字段不同。

There are concepts like Command Query separation that build on this idea that suggest an interface should either update state or query state, but not both. 有一些类似“命令查询分离”的概念都建立在该思想的基础上,建议接口应该更新状态或查询状态,但不能同时更新状态或查询状态。 Properties with both getters and setters provide an interface that both update state and query state. 带有getter和setter的属性提供了同时更新状态和查询状态的接口。 The above examples MoveTo and ChangeDate would be "commands". 上面的示例MoveToChangeDate将是“命令”。 Conceptually you would provide other ways of querying state; 从概念上讲,您将提供其他查询状态的方法。 if that's needed. 如果需要的话。

One of the other problems with properties is that people habitually add both getters and setters simply because it is a property. 属性的另一个问题之一是,人们仅仅因为它是一个属性就习惯性地同时添加了吸气剂和吸气剂。 The ability to get or set a property may not be necessary and simply adding both a getter and a setter by rote creates and interface that requires testing and maintenance that may not ever be needed. 可能不需要获得或设置属性的能力,只需简单地通过死记创建和接口同时添加getter和setter即可,而不需要进行测试和维护。

Subtle? 微妙? Sure; 当然; but he's talking about the object-oriented design, not code that "just works". 但是他在谈论的是面向对象的设计,而不是“有效”的代码。

You're ignoring "to do the work". 您将忽略“完成工作”。 If the work you want done is the brand of the car, then a getter that returns the brand does the work. 如果您要完成的工作是汽车的品牌,则返回该品牌的吸气剂即可完成工作。

What the article is saying is if you want work done on class data, put the work in the class. 文章的意思是,如果您希望对类数据进行处理,请将其放入类中。 Do not pull data out of the class, do work on it, then return it to the class: 不要从类中提取数据,对其进行处理,然后将其返回给类:

var c = new Car();
c.Odometer += 10;  // bad
c.DriveMiles(10);  // good

I also question how applicable that article is to C#; 我也质疑该文章对C#的适用性。 it claims: 它声称:

Getter and setter methods (also known as accessors) are dangerous for the same reason that public fields are dangerous: They provide external access to implementation details. getter和setter方法(也称为访问器)很危险,其原因与公共字段很危险:它们提供了对实现细节的外部访问。

In C# this is false, a C# accessor can accept arbitrary classes, they do not "provide external access to implementation details". 在C#中,这是错误的,C#访问器可以接受任意类,它们不“提供对实现细节的外部访问”。

Getters and setters are not evil, they just shouldn't be generated automaticaly for every attribute. getter和setter并不是邪恶的,只是不应该为每个属性自动生成它们。 As far as your example is concerned, a Car class should probably have a getBrand method returning a String, but a setter for this attribute is probably not needed. 就您的示例而言,一个Car类可能应该具有一个返回字符串的getBrand方法,但是可能不需要此属性的设置方法。 A method in Car returning a TextBox with the brand name is most probably worse idea than a simple getter returning a String, because it's not very generic. Car中返回品牌名称的TextBox的方法比返回字符串的简单getter方法更糟糕,因为它不是很通用。

I can see Peter Ritchie's answer now: good example with the changeDate. 我现在可以看到Peter Ritchie的答案:changeDate的好例子。 The Date class should provide a method like that rather than providing a getter for day and month and requiring user code to compute next day in the calendar on it's own. Date类应该提供类似的方法,而不是提供日和月的getter,并且需要用户代码自行计算日历中的第二天。

Basically what he's saying is, say you had a class with ten properties, and you wanted to dump it to a line of csv. 基本上,他的意思是说您有一个具有十个属性的类,并且您想将其转储到一行csv中。 Add a Tocsv method to the class to return a string with a pile of csvs in it. 将Tocsv方法添加到类中以返回其中包含一堆csvs的字符串。 Don't write an other class that accesses it through properties and builds the csv string as by necessity they become very tightly coupled. 不要编写通过属性访问它并构建csv字符串的其他类,因为它们必须紧密耦合。

Not sure why he singled out accessors, the proplem would be exactly they same with discrete methods to get and set, or worse still member variables. 不知道为什么要选出访问器,问题在于它们与获取和设置离散方法完全相同,或者更糟糕的是成员变量。

Obviously there are limits, you'd have to have really good reason for replacing 显然有限制,您必须有充分的理由更换

SomeLabel.Text = SomeInstance.StringValue;

with

SomeInstance.MakeStringValueALabel(SomeLabel);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM