简体   繁体   English

构造函数链接或使用命名/可选参数

[英]Constructor chaining or use named/optional parameters

I'm a very new programmer and understand we want to minimize code redundancy so when we update we can make as few changes as possible and also minimize errors.我是一个非常新的程序员,并且了解我们希望最大限度地减少代码冗余,因此当我们更新时,我们可以进行尽可能少的更改并最大限度地减少错误。

So I have a Student class that I want overloaded constructor so If I do back chaining it's like this.所以我有一个 Student 类,我想要重载构造函数,所以如果我做反向链接,它就像这样。

 public class Student
{
    string name;
    int Id;

    public Student()
    {
    }
    public Student(string name)
    {
        this.name = name;
    }
    public Student(string name, int Id) :this(name)
    {
        this.Id = Id;

But this is apparently bad because we want all the code in one constructor for what reason?但这显然很糟糕,因为我们出于什么原因想要在一个构造函数中包含所有代码? Ease of reading?阅读方便吗?

    public Student() : this(null, 0)
    { }
    public Student(string name) : this(name, 0)
    { }
    public Student(string name, int Id) 
    {
        this.name = name;
        this.Id = Id;
    }

If I do this forward chaining then what happens if we add a new field like string major?如果我做这个前向链接,那么如果我们添加一个像 string major 这样的新字段会发生什么? If I do forward chaining then I create a new overloaded constructor with the added field.如果我进行前向链接,那么我会使用添加的字段创建一个新的重载构造函数。 But now I have to change all the other constructors to call the new one.但是现在我必须更改所有其他构造函数以调用新的构造函数。 If I do backwards chaining I just create a new constructor and call the previous overloaded one.如果我进行反向链接,我只是创建一个新的构造函数并调用前一个重载的构造函数。

    public Student(string name, int Id, string major):this(name, Id)
    {
        this.major=major;
    } 

This seems like it follows OOP better but all examples in my text book show forward chaining and don't say why I shouldn't use back chaining.这似乎更好地遵循 OOP,但是我教科书中的所有示例都显示了前向链接,并且没有说明为什么我不应该使用后向链接。

If I used named/optional parameters it's even easier.如果我使用命名/可选参数,那就更容易了。

    public Student(string name = null, int Id = 0, string major = null)
    {
        this.name = name;
        this.Id = Id;
        this.major = major;
    }

And if I need another field I just have to edit the one and only constructor.如果我需要另一个字段,我只需要编辑唯一的构造函数。 This seems to follow OOP principles the best or am I mistaken?这似乎最好地遵循 OOP 原则还是我错了? It at least eliminates code duplication the most.它至少可以最大程度地消除代码重复。 My assignment was to "implement the student class following the principles of OOP".我的任务是“按照 OOP 的原则实施学生课程”。 I know all these are valid but is one way the best/accepted way of coding constructors?我知道所有这些都是有效的,但这是编码构造函数的最佳/公认方式之一吗? Are there shortcomings with named/optional params that I'm missing?我缺少的命名/可选参数是否存在缺陷? As a beginner it's very confusing that there's so many ways to code this.作为初学者,有很多方法可以对此进行编码,这非常令人困惑。

There is no best way , because they are different, each of them has advantages and disadvantages.没有最好的方法,因为它们是不同的,它们每个都有优点和缺点。

Independent constructors and chained constructors are available since C# 1.0, under most circumstances we use chained constructors but sometimes we have to use the former if the two constructors has totally different things to handle.从 C# 1.0 开始就可以使用独立构造函数和链式构造函数,大多数情况下我们使用链式构造函数,但有时如果两个构造函数要处理的事情完全不同,我们必须使用前者。

class Student
{
    public Student()
    {
        DoSomething();
    }

    public Student(string name)
    {
        this.Name = name;
        DoAnotherThing();
    }
}

Comparing with optional parameters constructor, the above two are much longer, but to be honest, they are much safer.与可选参数构造函数相比,上面两个要长得多,但说实话,它们更安全。 Consider the following case:考虑以下情况:

public class Student
{
    public Student(string firstName = null, string lastName = null)
    {
        this.FirstName = firstName;
        this.LastName = lastName;
    }

    public string FirstName { get; set; }
    public string LastName { get; set; }
}

//it's working fine
//var danny = new Student("danny", "chen");

//as the business grows a lot of students need a middle name
public Student(string firstName = null, string middleName = null, string lastName = null)
{
    this.FirstName = firstName;
    this.MiddleName = middleName;
    this.LastName = lastName;
}

//for a better sequence the programmer adds middleName between the existing two, bang!

Another difference between them is using reflection.它们之间的另一个区别是使用反射。 Optional parameters will not generate more constructors for you, and the default values will not be applied if you are invoking the constructor using reflection.可选参数不会为您生成更多构造函数,如果您使用反射调用构造函数,则不会应用默认值。

I know all these are valid but is one way the best/accepted way of coding constructors?我知道所有这些都是有效的,但这是编码构造函数的最佳/公认方式之一吗?

Not to the best of my knowledge - you have many options.据我所知,不是 - 你有很多选择。 Your colleagues are the best people to talk to to reach a consensus.您的同事是达成共识的最佳人选。 C# is becoming a very rich language, and that means that there will be many different ways to achieve the same thing. C# 正在成为一种非常丰富的语言,这意味着将有许多不同的方法来实现同一件事。

Are there shortcomings with named/optional params that I'm missing?我缺少的命名/可选参数是否存在缺陷?

Not to the best of my knowledge.据我所知,不是。 Personally I think this is the best solution, but others may differ.我个人认为这是最好的解决方案,但其他人可能会有所不同。

As a beginner it's very confusing that there's so many ways to code this.作为初学者,有很多方法可以对此进行编码,这非常令人困惑。

Welcome to programming.欢迎编程。 There's millions of us programmers, and we're all busy adding complexity to the world!我们有数以百万计的程序员,我们都在忙着给世界增加复杂性!

I suggest looking deeper about this assumption :我建议更深入地了解这个假设:

"But this is apparently bad because we want all the code in one constructor for what reason" “但这显然很糟糕,因为我们出于什么原因希望在一个构造函数中包含所有代码”

There is Fluent Interface Pattern that puts these things apart, also I can not strongly argue that this directly translates for constructors.Fluent Interface Pattern将这些东西分开,我也不能强烈认为这直接转换为构造函数。

customer
    .NameOfCustomer("Shiv")
    .Bornon("12/3/1075")
    .StaysAt("Mumbai");

Illustrative implementation :说明性实施:

public class Customer
{
    public string FullName { get; set; }
    public DateTime DateOfBirth { get; set; }
    public string Address { get; set; }

    public Customer NameOfCustomer(string name)
    {
        this.FullName = name;
        return this;
    }

    public Customer BornOn(DateTime dateOfBirth)
    {
        this.DateOfBirth = dateOfBirth;
        return this;
    }

    public Customer StaysAt(string address)
    {
        this.Address = address;
        return this;
    }
} 

Example source 示例源

This is a partial answer.这是部分答案。 Your "backwards chaining", with one constructor setting some parameter(s) then calling another constructor for the rest, is very reasonable/sensible for normal functions : one function does part of the work, then calls another function for some other work, and so on.您的“向后链接”,一个构造函数设置一些参数,然后为其余的调用另一个构造函数,对于普通函数来说是非常合理/明智的:一个函数完成部分工作,然后调用另一个函数进行其他工作,并且等等。

But for public constructors, any one of them can be called by client code, expecting to get a fully constructed object , fully initialized.但是对于公共构造函数,它们中的任何一个都可以被客户端代码调用,期望得到一个完全构造的对象,完全初始化。 Some constructors in your example leave members uninitialized (unless what you want is the default value for the type).您示例中的某些构造函数未初始化成员(除非您想要的是该类型的默认值)。

As an alternative, you can have private constructors.作为替代方案,您可以拥有私有构造函数。

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

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