Вызов одного конструктора из другого

663

У меня есть два конструктора, которые передают значения полям только для чтения.

class Sample
{
    public Sample(string theIntAsString)
    {
        int i = int.Parse(theIntAsString);

        _intField = i;
    }

    public Sample(int theInt)
    {
        _intField = theInt;
    }


    public int IntProperty
    {
        get { return _intField; }
    }
    private readonly int _intField;

}

Один конструктор получает значения напрямую, а другой выполняет некоторые вычисления и получает значения, а затем устанавливает поля.

Теперь вот catch:

  • Я не хочу дублировать установочный код. В этом случае только один поле, но, конечно, может лучше быть более чем одним.
  • Чтобы сделать поля только для чтения, мне нужно установить их из конструктора, так что Я не могу "извлечь" общий код для функция полезности.
  • Я не знаю, как позвонить конструктор из другого.

Любые идеи?

Теги:
constructor

7 ответов

1136
Лучший ответ

Вот так:

public Sample(string str) : this(int.Parse(str)) {
}
  • 52
    @Avi: Вы можете создать static метод, который манипулирует параметрами.
  • 14
    Могу ли я узнать порядок исполнения этого? Все в Sample(string) будет выполнено первым, затем Sample(int) или версия int будет выполнена первой, а затем вернется к строковой версии? (Как вызов super() в Java?)
Показать ещё 19 комментариев
115

Если то, что вы хотите, не может быть удовлетворительно достигнуто без инициализации в своем собственном методе (например, потому что вы хотите сделать слишком много до кода инициализации или обернуть его в try-finally или что-то еще), вы можете любой или все конструкторы передают переменные readonly по ссылке на процедуру инициализации, которая затем сможет манипулировать ими по желанию.

class Sample
{
    private readonly int _intField;
    public int IntProperty
    {
        get { return _intField; }
    }

    void setupStuff(ref int intField, int newValue)
    {
        intField = newValue;
    }

    public Sample(string theIntAsString)
    {
        int i = int.Parse(theIntAsString);
        setupStuff(ref _intField,i);
    }

    public Sample(int theInt)
    {
        setupStuff(ref _intField, theInt);
    }
}
  • 16
    +1 реальное решение. Используя base(...) или this(...) мы можем выполнять только очень ограниченные операции.
  • 2
    Абсолютно согласен - другое решение работает, но это просто неправильный способ сделать это (ТМ)!
Показать ещё 9 комментариев
41

Перед телом конструктора используйте:

: base (parameters)

: this (parameters)

Пример:

public class People: User
{
   public People (int EmpID) : base (EmpID)
   {
      // Add more statements here.
   }
}
  • 12
    К сожалению, не работает, если мне нужно несколько операций над аргументами между вызовами конструкторов.
  • 0
    @ Денис Разве вы не можете связать конструктор в середине, чтобы добиться того же эффекта?
Показать ещё 1 комментарий
8

Я улучшаюсь после ответа supercat. Я думаю, что также можно сделать следующее:

class Sample
{
    private readonly int _intField;
    public int IntProperty
    {
        get { return _intField; }
    }

    void setupStuff(ref int intField, int newValue)
    {
        //Do some stuff here based upon the necessary initialized variables.
        intField = newValue;
    }

    public Sample(string theIntAsString, bool? doStuff = true)
    {
        //Initialization of some necessary variables.
        //==========================================
        int i = int.Parse(theIntAsString);
        // ................
        // .......................
        //==========================================

        if (!doStuff.HasValue || doStuff.Value == true)
           setupStuff(ref _intField,i);
    }

    public Sample(int theInt): this(theInt, false) //"false" param to avoid setupStuff() being called two times
    {
        setupStuff(ref _intField, theInt);
    }
}
  • 3
    Возможно, это позволит третьей стороне создать семпл без его настройки, вызвав new Sample(str, false) .
  • 0
    Это не компилируется.
Показать ещё 2 комментария
6

Вот пример, который вызывает другой конструктор, затем проверяет его свойство.

    public SomeClass(int i)
    {
        I = i;
    }

    public SomeClass(SomeOtherClass soc)
        : this(soc.J)
    {
        if (I==0)
        {
            I = DoSomethingHere();
        }
    }
  • 0
    Это потенциально намного чище, если вы используете конструктор по умолчанию для некоторых случаев и делаете небольшие / специфические изменения для других.
0

Да, вы можете вызвать другой метод раньше, чем база вызовов или это!

public class MyException : Exception
{
    public MyException(int number) : base(ConvertToString(number)) 
    {
    }

    private static string ConvertToString(int number) 
    { 
      return number.toString()
    }

}
  • 3
    Просто ради общего ответа - если ваш конструктор должен инициализировать какие-либо поля только для чтения, вы не можете использовать методы для этого.
0

Когда вы наследуете класс из базового класса, вы можете вызвать конструктор базового класса, создав производный класс

class samle {
    public int x;

    public sample(int value) {
        x = value;
    }
}

class der : public sample {
    public:
        int a;
        int b;

        public der(int value1,int value2) : base(50) {
            a = value1;
            b = value2;
        }

        class run {
            public static void main(String[] args){
                der obj = new der(10,20);
                Console.WriteLine(obj.x);
                Console.WriteLine(obj.a);
                Console.WriteLine(obj.b);
            }
        }

Вывод программы

50 10 20

Вы также можете использовать это ключевое слово для вызова конструктора из другого конструктора

class samle {
    public int x;

    public sample(int value) {
        x = value;
    }

    public sample(sample obj):this(obj.x) {
    }
}

class run{
    public static void main(String[] args) {
        sample s = new sample(20);
        sample ss = new sample(s);
        Console.WriteLine(ss.x);
    }
}

Выход равен 20.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню