C# 构造函数
有人可以建议我在编写 C#
构造函数时采取什么方法吗?
在其他语言中,例如 C++,一切都很好 - 您通常不会使内部字段可见并为它们提供 getter / setter。
这意味着,您可以为您的类提供构造函数,它初始化所有/部分本地成员并感到高兴。
然而,C#
具有 properties
,它允许我们编写如下内容:
Class x = new Class { Field1 = new Field1 ...., Field2 = new Field2 }
这允许链接对象构造,并且正如我假设的那样,可以删除许多构造函数,这如果我们没有属性
,则需要。
正如我所假设的,将其与属性的默认值相结合,我们可以完全摆脱非专用构造函数,它们实际上做了一些工作。
现在 - 可以删除冗余构造函数并允许通过字段初始化构造对象?
这种方法有什么缺点?有人可以提供有关组合使用字段和构造函数的一般建议以及一些经验法则
吗?
谢谢。
Could someone advice me on what approach to take when writing C#
constructors?
In other languages, like C++
, everything is fine - you usually don't make the internal fields visible and provide getters / setters for them.
This means, you could provide your class with constructors, which initialize all / some of your local members and be happy.
C#
, however, has properties
, which allows us to write something like:
Class x = new Class { Field1 = new Field1 ...., Field2 = new Field2 }
This allows chaining for the object construction and, as I assume, can remove a lot of constructors, which would be required if we didn't have properties
.
Combining this with default values for properties, as I assume, we can completely get rid of non-specialized constructors, which actually do some work.
Now - is it okay to remove redundant constructors and allow object constructing via field initializing?
What are the drawbacks of this approach? Could someone give general recommendations about combining the usage of fields and constructors, some rules of thumb
, probably?
Thank you.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
我自己的经验法则很简单:如果需要某些东西来完全构造对象,那么它应该是一个 ctor 参数。
一个很好的例子是 Stream 辅助对象之一,例如 StreamReader 或 BinaryReader。如果没有关联的 Stream 对象,它们就无法运行,因此必须在构造函数中指定。
My own rule of thumb is simple: If something is required to completely construct the object, it should be a ctor parameter.
A good example is one of the Stream helper objects like StreamReader or BinaryReader. They cannot function without an associated Stream object, so that must be specified in the constructor.
在我看来,拥有所谓的冗余构造函数并没有什么问题。如果您有足够的理由想要定义构造函数,那可能是因为确实需要这样做。
In my opinion, there is nothing wrong with having what you term as redundant constructors. If it makes enough sense for you to want to define a constructor, it is probably because there's a genuine need to do it that way.
构造函数可用于强制使用者向类提供值。
我的经验法则是,字段用于可选数据,而构造函数可用于强制所需数据。
不过,这个问题有点错误的二分法。 C++ 的行为方式与 C# 相同 - “字段”(实际上是属性 - 字段是类级变量)通常用作设置内部值的 getter/setter,并且
new
语法允许您设置字段只是一个简写Constructors can be used to force the consumer to supply values to the class.
My rule of thumb is that Fields are for optional data, while constructors can be used to force required data.
The question is something of a false dichotomy though. C++ behaves the same way as C# - "Fields" (which are actually properties - fields are class-level variables) are generally used as getters/setters for setting internal values, and the
new
syntax which allows you to set fields is just a shorthand for最佳实践是创建一个处于可用状态的对象;尝试限制对财产设置者的依赖。
它减少了创建不完整对象的机会,并减少了脆弱的代码。
Best practice is to create an object in a usable state; try to limit reliance on property setters.
It reduces the chances that you create an object which is incomplete and leads to less fragile code.
您发布的代码使用了所谓的对象初始化程序,它们实际上只是最近引入的语法糖。使用对象初始值设定项只是调用构造函数和设置属性的一种简写方式。您应该继续在 C# 中使用构造函数,就像在其他语言中使用构造函数一样 - 一般规则是,如果类需要一个对象或值才能正确初始化,则该参数应该通过构造函数传递。如果不需要该值,则将其设为可设置属性是合理的。
一般来说,我会尽可能避免使用 setter(在很多情况下这是不可能的)。
The code you posted is using what are called Object Initializers, which are really just syntactic sugar that were introduced fairly recently. Using object initializers are just a shorthand way of calling a constructor and setting properties. You should continue to use constructors in C# the same way that you have used them in other languages--the general rule is that if a class requires an object or value for it to be initialized properly, that parameter should be passed through the constructor. If the value isn't required, it is reasonable to make it a settable property.
Generally speaking, I avoid using setters at all when possible (there are many, many cases when it's not possible).
在 XAML 中使用公共无参数构造然后进行属性初始化的方法很流行(必需?),很多 WPF 玩具都这样做。
您面临的唯一问题是部分初始化的对象,但是您可以在尝试使用字段之前简单地验证对象状态。
就我个人而言,我在构造函数中创建了关键值参数,我从对象的副本和一系列可选参数中创建了复制构造函数,而且我还没有创建需要 XAML 使用的东西。
The approach of public parameterless construction followed by property initialization is popular (required?) for use in XAML, a lot of WPF toys do this.
The only problem you face is a partially initialized object, but then you can simply validate object state prior to attempting to use the fields.
Personally, I make critical values parameters in the constructor, I make copy constructors out of a copy of the object and a range of optional parameters, and I've yet to make something that needs consuming by XAML.
对象初始值设定项语法只是一个语法糖。即使在 C# 1 中,您也可以编写
C# 3 ,基本上将语法缩短为:
构造函数的要点不仅仅是设置字段,构造函数应该根据参数逻辑地构造对象,以便当构造函数返回时,您可以执行以下操作: get 是一个可以使用的对象。
The object initializer syntax is just a syntactic sugar. Even in C# 1 you could write
C# 3 basically shortens the syntax to:
The point od the counstructor is not to just set the fields, the constructor should logically construct the object, based on the parameters, so that when the constructor returns, what you get is an object that is ready to be used.
可以吗?好吧,这取决于......
为了使用对象初始化程序,您需要将公共设置器公开给您的所有字段,您可能不希望这样做。如果您乐意公开它们,那么我会说继续删除构造函数。然而,仅仅因为您可以做某事并不意味着您应该。我想说,如果您发现所有字段都是可公开设置的,则应该删除构造函数,而不是仅仅为了允许您删除构造函数而使字段可设置。
Is it OK? Well, that depends...
In order to use object initialisers you will need to expose public setters to all your fields, you may not want this. If you are happy to expose them then I'd say go ahead and remove constructors. However just because you can do someting does not mean you should. I would say removing the constructors should be something you do if you find all your fields are publicly settable, do not make the fields settable just to allow you to remove the constructor.
我怀疑您在这里指的是域对象,但就服务而言,通过构造函数注入服务的依赖项使服务更加自我记录,而不是“更新”您的依赖项。此外,这使您可以更轻松地使用依赖项注入容器。
I suspect you are referring to domain objects here, but in the case of services, injecting the dependencies of the service in through a constructor makes the service more self documenting, as opposed to "newing up" your dependencies. Additionally this sets you up to use dependency injection containers more easily.