如何使用多个构造函数来消除重复代码并保持可读性?(该问题涉及IT技术)

48
int a, b, c;

Constructor()
{
    a = 5;
    b = 10;
    c = 15;
    //do stuff
}
Constructor(int x, int y)
{
    a = x;
    b = y;
    c = 15;
    //do stuff
}
Constructor(int x, int y, int z)
{
    a = x;
    b = y;
    c = z;
    //do stuff
}

为了避免“东西”的重复和减少一些赋值操作,我尝试了以下方法:

int a, b, c;

Constructor(): this(5, 10, 15)
{
}
Constructor(int x, int y): this(x, y, 15)
{
}
Constructor(int x, int y, int z)
{
    a = x;
    b = y;
    c = z;
    //do stuff
}

这个对我想做的事情有用,但有时我需要使用一些冗长的代码来创建新对象或进行一些计算:

int a, b, c;

Constructor(): this(new Something(new AnotherThing(param1, param2, param3),
    10, 15).CollectionOfStuff.Count, new SomethingElse("some string", "another
    string").GetValue(), (int)Math.Floor(533 / 39.384))
{
}
Constructor(int x, int y): this(x, y, (int)Math.Floor(533 / 39.384))
{
}
Constructor(int x, int y, int z)
{
    a = x;
    b = y;
    c = z;
    //do stuff
}

这段代码与之前几乎相同,只是传递的参数不太易读。我更喜欢做这样的事情:

int a, b, c;

Constructor(): this(x, y, z) //compile error, variables do not exist in context
{
    AnotherThing at = new AnotherThing(param1, param2, param3);
    Something st = new Something(aThing, 10, 15)
    SomethingElse ste = new SomethingElse("some string", "another string");

    int x = thing.CollectionOfStuff.Count;
    int y = ste.GetValue();
    int z = (int)Math.Floor(533 / 39.384);

    //In Java, I think you can call this(x, y, z) at this point.
    this(x, y, z); //compile error, method name expected
}
Constructor(int x, int y): this(x, y, z) //compile error
{
    int z = (int)Math.Floor(533 / 39.384);
}
Constructor(int x, int y, int z)
{
    a = x;
    b = y;
    c = z;
    //do stuff
}
基本上我正在构建构造函数内的参数。然后我尝试将这些构建好的参数传递给另一个构造函数。我记得在Java中编码时,可以使用"this"和"super"关键字在另一个构造函数体内调用构造函数。但是在C#中似乎不可能。
有没有一种简单的方法可以做到这点?我做错了什么吗?如果不可能的话,我应该坚持难以阅读的代码吗?
我想我可以将重复的代码剪切成完全位于构造函数之外的另一个方法。然后每个构造函数只需要执行自己的操作并调用其他构造函数共享的代码。
2个回答

45

作为调用所有构造函数的初始化方法的替代方案(这将防止您使用readonly字段)或工厂方法(当您拥有派生类时引入额外的复杂性),您可以使用参数对象

int a, b, c;

public Constructor()
    : this(new ConstructorParameters())
{
}

public Constructor(int x, int y)
    : this(new ConstructorParameters(x, y))
{
}

public Constructor(int x, int y, int z)
{
    a = x;
    b = y;
    c = z;
    //do stuff 
} 

private Constructor(ConstructorParameters parameters)
    : this(parameters.X, parameters.Y, parameters.Z)
{
}

private class ConstructorParameters
{
    public int X;
    public int Y;
    public int Z;

    public ConstructorParameters()
    {
        AnotherThing at = new AnotherThing(param1, param2, param3); 
        Something st = new Something(at, 10, 15) 
        SomethingElse ste = new SomethingElse("some string", "another string"); 

        X = st.CollectionOfStuff.Count; 
        Y = ste.GetValue(); 
        Z = (int)Math.Floor(533 / 39.384); 
    }

    public ConstructorParameters(int x, int y)
    {
        X = x;
        Y = y;
        Z = (int)Math.Floor(533 / 39.384);
    }
}

我认为我可能会喜欢这条路比工厂方法更好。我对使用工厂方法修改我的代码感到犹豫,主要是因为我正在使用继承。作为一个菜鸟程序员,我很难想象所有需要进行的更改。在我的基类中有一些重载的构造函数。派生类然后向基本构造函数添加自己的组成部分。根据派生类,需要不同的计算来找到某些参数。使用私有类来处理复杂参数似乎是更简单的方法。 - Cheese
我决定使用另一种解决方案。阅读了你发布的链接后,我开始阅读同一网站上的“参数太多”页面。通过阅读,我想到也许是所有传递给构造函数的参数使构造函数变得过于复杂了。我已经决定从构造函数中删除大部分参数。设置这些字段将在代码的其他位置完成。我的实际问题不是“如何使用构造函数实现这个?”,而是“我真的需要传递那么多参数吗?”由于你提供的链接帮助我找到了答案... - Cheese
您发布的答案是我认为最好的解决方案,因此我选择您的回答作为答案。 - Cheese

27
你可以这样做。
Constructor() : this(5, 10, 15)
{
}
Constructor(int x, int y) : this(x, y, 15)
{
}
Constructor(int x, int y, int z)
{
  int a = x;
  int b = y;
  int c = z;
  //do stuff
}

然而,如果你需要根据参数进行一些高级逻辑操作,我建议使用工厂模式

public class myclass
{
  private myclass(int x, int y, int z)
  {
    int a = x;
    int b = y;
    int c = z;
    //do stuff
  }
  public static myclass Create()
  {
    AnotherThing at = new AnotherThing(param1, param2, param3);
    Something st = new Something(aThing, 10, 15)
    SomethingElse ste = new SomethingElse("some string", "another string");

    int x = thing.CollectionOfStuff.Count;
    int y = ste.GetValue();
    int z = (int)Math.Floor(533 / 39.384);

    return new myclass(x, y ,z);
  }
  public static myclass Create(int x, int y)
  {
    if (x = 1)
      return new myclass(x, y, 2)
    else 
      return new myclass(x, y, 15);
  }
  public static myclass Create(int x, int y, int z)
  {
    //so on and so forth
    return new myclass(x, y, z);
  }
}

虽然你不一定需要工厂模式,但它确实可以使你的构造函数逻辑更加易读。


我认为这是我试图实现的一个不错的解决方案。我的项目包含多个类,将用于创建匿名对象的集合。我认为工厂模式可以应用于我的代码中的多个位置。 - Cheese
为什么在C#中不能直接调用另一个构造函数?(如果可以的话) - Makan
@MakanTayebi 当然,有时候如果参数无效,您不想构造一个对象。如果是这种情况,大多数情况下最好使用工厂模式,而不是在构造函数中抛出异常。 - Erik Philips

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接