Вопрос по this, constructor, c# – Как я могу использовать несколько конструкторов для удаления дублированного кода при сохранении читабельности?

37
<code>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
}
</code>

Чтобы не допустить дублирования «материала» и нескольких заданий, я попробовал что-то вроде:

<code>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
}
</code>

Это работает для того, что я хочу сделать, но иногда мне нужно использовать какой-то длинный код для создания новых объектов или сделать некоторые вычисления:

<code>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
}
</code>

Этот код почти такой же, как и раньше, только передаваемые параметры не очень читабельны. Я бы предпочел сделать что-то вроде:

<code>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
}
</code>

В основном я строю параметры в теле конструктора. Затем я пытаюсь передать эти встроенные параметры другому конструктору. Я думаю, что помню возможность использовать ключевые слова "this" и "super" для вызова конструкторов внутри тела другого конструктора при кодировании в Java. Это не представляется возможным в C #.

Есть ли способ сделать это легко? Я сделал что-то неправильно? Если это невозможно, я должен просто придерживаться нечитаемого кода?

Полагаю, я всегда мог вырезать дублированный код в другом методе полностью вне конструкторов. Тогда каждый конструктор будет делать свое дело и вызывать код, используемый другими конструкторам

Ваш Ответ

2   ответа
38

ров (что не позволяет использоватьreadonly fields) или фабричные методы (которые вносят дополнительную сложность, когда у вас есть производные классы), вы можете использовать параметр объекта:

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
18

Ты можешь сделат

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
@ MakanTayebi конечно, но иногда вы не хотите создавать объект, если параметры неверны. Если это так, то в большинстве случаев лучше использовать фабричный шаблон, а затем создавать исключение в конструкторе. Erik Philips
Почему в C # нельзя просто вызвать функцию конструктора в другом конструкторе? (Если так Makan Tayebi

Похожие вопросы