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

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

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

    public Sample(int theInt) => _intField = theInt;
    public int IntProperty    => _intField;

    private readonly int _intField;
}

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

Теперь здесь подвох:

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

Есть идеи?

Ответ 1

Как это:

public Sample(string str) : this(int.Parse(str)) { }

Ответ 2

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

public class Sample
{
    private readonly int _intField;
    public int IntProperty => _intField; 

    private 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);
}

Ответ 3

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

: base (parameters)

: this (parameters)

Пример:

public class People: User
{
   public People (int EmpID) : base (EmpID)
   {
      // Add more statements here.
   }
}

Ответ 4

Я улучшаюсь после ответа 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);
    }
}

Ответ 5

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

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

    public SomeClass(SomeOtherClass soc)
        : this(soc.J)
    {
        if (I==0)
        {
            I = DoSomethingHere();
        }
    }

Ответ 6

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

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

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

}

Ответ 7

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

class sample
{
    public int x;

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

class der : sample
{
    public int a;
    public 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);

        System.Console.WriteLine(obj.x);
        System.Console.WriteLine(obj.a);
        System.Console.WriteLine(obj.b);
    }
}

Выход примера программы равен

50 10 20


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

class sample
{
    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);

        System.Console.WriteLine(ss.x);
    }
}

Результат этой примера программы -

20

Ответ 8

Цепочка конструктора, т.е. вы можете использовать "Base" для отношения Is и "This" вы можете использовать для одного и того же класса, когда вы хотите вызвать несколько Constructor за один вызов.

  class BaseClass
{
    public BaseClass():this(10)
    {
    }
    public BaseClass(int val)
    {
    }
}
    class Program
    {
        static void Main(string[] args)
        {
            new BaseClass();
            ReadLine();
        }
    }

Ответ 9

Обработка ошибок и повторное использование вашего кода является ключевым. Я добавил строку к проверке int, и при необходимости можно добавить другие типы. Решение этой проблемы с помощью решения для повторного использования может быть следующим:

public class Sample
{
    public Sample(object inputToInt)
    {
        _intField = objectToInt(inputToInt);
    }

    public int IntProperty => _intField;

    private readonly int _intField;
}

public static int objectToInt(object inputToInt)
{
    switch (inputToInt)
        {
            case int inputInt:
                return inputInt;
            break;
            case string inputString:
            if (!int.TryParse(inputString, out int parsedInt))
            {
                throw new InvalidParameterException($"The input {inputString} could not be parsed to string");
            }
            return parsedInt;

            default:
                throw new InvalidParameterException($"Constructor do not support {inputToInt.GetType().Name}");
            break;
        }
}