Подтвердить что ты не робот

Вызов переопределенного конструктора и базового конструктора в С#

У меня есть два класса: Foo и Bar, которые имеют такие конструкторы:

class Foo
{
    Foo()
    {
      // do some stuff
    }

    Foo(int arg)
    {
      // do some other stuff
    }
}

class Bar : Foo
{
    Bar() : base()
    {
      // some third thing
    }
}

Теперь я хочу представить конструктор для Bar, который принимает int, но я хочу, чтобы материал, который происходит в Bar(), запускался так же, как и материал из Foo (int). Что-то вроде этого:

Bar(int arg) : Bar(), base(arg)
{
  // some fourth thing
}

Есть ли способ сделать это на С#? Лучшее, что я до сих пор делаю, делает работу Bar() функцией, которая также вызывается Bar (int), но это довольно неэлегантно.

4b9b3361

Ответ 1

Нет, это невозможно. Если вы используете Reflector для проверки IL, сгенерированного для каждого конструктора, вы поймете, почему - вы в конечном итоге вызываете оба конструктора для базового класса. Теоретически, компилятор мог построить скрытые методы для выполнения того, что вы хотите, но действительно нет никакого преимущества перед тем, что вы делаете то же самое явно.

Ответ 2

Я бы повторно создал конструкторы, поэтому они называются как

Bar() : this(0) 
Bar(int) : Foo(int) initializes Bar
Foo(int) initializes Foo
Foo() : this(0) 

Это подходит, если конструкторы без параметров принимают какое-то значение по умолчанию для параметра int другого конструктора. Если конструкторы не связаны друг с другом, вы, вероятно, делаете что-то не так с вашим типом, или, может быть, нам нужна дополнительная информация о том, чего вы пытаетесь достичь.

Ответ 3

Я бы рекомендовал изменить цепочку конструкторов, чтобы перейти от наименее специфичной к наиболее конкретной.

class Foo
{
    Foo()
    {
      // do some stuff
    }

    Foo(int arg): this()
    {
      // do some other stuff
    }
}

class Bar : Foo
{
    Bar() : Bar(0)
    {
      // some third thing
    }

    Bar(int arg): base(arg)
    {
      // something
    }
}

Любое создание объекта Bar теперь вызовет все 4 конструктора. Цепочка конструктора должна обеспечивать значения по умолчанию для более конкретных конструкторов, а не наоборот. Вы должны действительно посмотреть на то, что вы пытаетесь выполнить, и убедиться, что вы делаете, имеет смысл. Курт прав, что есть технические причины, по которым вы не можете этого сделать, но есть также логические причины, почему вы не должны.

Ответ 4

Это единственное, о чем я могу думать...

 public class Foo
{
    public Foo()
    {
    }
    public Foo(int? arg): this()
    {
    }

}
public class Bar : Foo
{
    private int x;
    public Bar(): this(new int?()) // edited to fix type ambiguity
    {
        // stuff that only runs for paramerless ctor
    }
    public Bar(int? arg)
        : base(arg)
    {
        if (arg.HasValue)
        {
            // Do stuff for both parameterless and parameterized ctor
        }
        // Do other stuff for only parameterized ctor
    }
}

Ответ 5

У вас нет конструктора Bar, который принимает int, вызывает конструктор без параметров?

Ответ 6

Вы можете поместить материал из Bar() в Bar (int) и Bar (int) вызова с помощью Bar() со значением по умолчанию? Тогда Bar (int) может вызвать базовый конструктор.

class Bar : Foo
{
    Bar() : this(0)
    {
    }

    Bar(int arg) : base(arg)
    {
    }
}

Это точно не отвечает на ваш вопрос, но в зависимости от вашего сценария может быть работоспособным решением.

Ответ 7

можете ли вы взять код инициализации для Bar() и сделать его методом и вызвать его из обоих конструкторов, а новый конструктор просто вызвать base (arg)?

Ответ 8

Вы можете использовать этот код:

public Foo
{
    public Foo()
    {
        this.InitializeObject();
    }

    public Foo(int arg) : this()
    {
        // do something with Foo arg
    }

    protected virtual void InitializeObject()
    {
        // initialize object Foo
    }
}

public Bar : Foo
{
    public Bar : base() { }

    public Bar(int arg) : base(arg)
    {
       // do something with Bar arg
    }

    protected override void InitializeObject()
    {
       // initialize object Bar

       base.InitializeObject();
    }
}

Просто переопределите метод InitializeObject(), как в приведенном выше коде, и поместите весь свой код, который вы хотите разместить в конструкторе без параметров. И, наконец, наберите base.InitializeObject() в конце кода.

Надеюсь, это полезно.