Вызов переопределенного конструктора и базового конструктора в C # - PullRequest
49 голосов
/ 02 декабря 2008

У меня есть два класса, 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
}

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

Ответы [ 8 ]

32 голосов
/ 02 декабря 2008

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

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

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

24 голосов
/ 02 декабря 2008

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

13 голосов
/ 02 декабря 2008

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

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 конструктора. Цепочка конструктора должна предоставлять значения по умолчанию для более конкретных конструкторов, а не наоборот. Вы должны действительно посмотреть на то, что вы пытаетесь достичь, и убедиться, что то, что вы делаете, имеет смысл. Курт прав, что есть технические причины, по которым вы не можете этого сделать, но есть и логические причины, по которым вы не должны этого делать.

3 голосов
/ 02 декабря 2008

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

 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
    }
}
1 голос
/ 02 декабря 2008

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

1 голос
/ 02 декабря 2008

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

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

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

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

1 голос
/ 02 декабря 2008

Разве вы не можете иметь конструктор Bar, который принимает int для вызова конструктора без параметров?

0 голосов
/ 30 апреля 2013

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

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

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

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

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

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

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

       base.InitializeObject();
    }
}

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...