2009-02-05 2 views
3

Может ли кто-нибудь дать мне 1 вескую причину, почему в C# цепной конструктор всегда вызывается перед любым из тела конструктора?1 хорошая причина, почему вначале вызываются цепные конструкторы?

.NET позволяет вам вызвать цепной конструктор в любой точке внутри конструктора, поэтому почему C# заставляет вас делать это до выполнения вашего тела конструктора?

Однажды я написал Андерсу Х и спросил его об этом, и он был достаточно любезен, чтобы тратить время на ответ, несмотря на то, насколько он занят. К сожалению, ему удалось ответить на вопрос, о котором я действительно не спрашивал (о названных конструкторах.)

Так что, просто из любопытства, я думал, что попрошу здесь, потому что лично я не думаю, что для этого есть веская причина ограничение, поэтому, надеюсь, я буду перевоспитан :-)

Просто уточнить. Правило CLR .NET состоит в том, что должен быть вызван 1 конструктор, только 1 конструктор и только один раз. Таким образом, в CLR они действительны

public class Meh 
{ 
    public Meh() 
    { 
    Console.WriteLine("Meh()"); 
    this("Hello"); 
    } 

    public Meh(string message) 
    { 
    Console.WriteLine("Meh {0}", message); 
    base(); 
    } 
} 

Но не в C#

+0

В большинстве ответов до сих пор предполагается, что вы говорите о вызове конструкторов базового класса. Однако, я думаю, вы говорите о вызове других конструкторов для текущего класса, подобных этому (некоторые, другие, args); Что он? –

ответ

0

Если была истинная причина, почему эта способность не должна предоставляться, она не будет поддерживаться CLR или другими языками .NET. Я могу только заключить, что ответ один из тех, «Потому что это всегда было так», и ограничение, вероятно, просто было скопировано с C++ или что-то в этом роде.

0

Так вы говорите, «субъективный» Я полагаю, вы не просите историческую причину; так:

  1. Вот как это делает C++.
  2. Зачем вам не нужен базовый класс?
  3. Стоит ли сделать язык более сложным, чтобы разместить любой редкий случай использования, который вы упомянули в качестве ответа на «2.»?
+0

Честно говоря, я сомневаюсь, что (1) считалось, что г-н Хельсберг и его команда, как известно, не разработали язык с такой «обратной совместимостью». –

+0

Это как может быть. Но у C++ есть [хорошие] причины для того, чтобы делать это так, как это делает, о котором OP, вероятно, уже знает ... потому что C# делает то же самое, что и C++, я полагаю, что эти же веские причины относятся и к C#. – ChrisW

+0

Я вообще не знаю C++, поэтому я не знаю веских причин, но эти причины не существуют в CLR, потому что это допускают другие языки .NET. –

6

Выполнение первого выполнения конструктора с цепочкой гарантирует, что все элементы базового класса по меньшей мере доступны в производном классе, поскольку они находятся в базе. Разрешить выполнение цепного конструктора в произвольной точке было бы компромиссом с небольшой заметной выгодой.

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

+0

"выполнить элементы first..base класса .. доступны в ..деланных .. в базе". Таким образом, называет это любой момент, прежде чем вы к ним обращаетесь. «исключающей ленивым создание» Я понятия не имею, что вы имеете в виду :-) «Run конструктор дважды» компилятор может предотвратить это, и CLR будет сгенерировано исключение в любом случае. –

+0

«Вызов в любой момент до вашего доступа» является синонимом «ленивого создания». Если вы оставите это до компилятора, чтобы вызвать базовый конструктор, когда вы обращаетесь к элементу, определяющему его базу, вы не можете привязать точку выполнения этого же конструктора в коде. –

0

Таким образом, это согласуется с базовыми конструкторами. Базовые конструкторы вызываются перед вашим конструктором, когда вы ссылаетесь на них: base(), поэтому имеет смысл, что:() имеет ту же семантику.

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

0

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

(Я предполагаю, что у вас не будет конструктора без параметров, который ничего не делает. У меня не может быть этого в моей ситуации, так как это требование не должно быть такого.)

Я не вижу элегантного решения.

1

/* Так как вы можете сделать ниже прокомментировал код, как в Дельфах общественного класса BaseClass { общественных BaseClass (строка sSql) { ExecSQL (sSql); // выполнить запрос }}

public class DerivedClass : BaseClass 
{ 
    public DerivedClass(int i, DateTime dt) 
    { 
     string sSql = ""; 
     //construct sSql based on i, dt 
     base(sSql); 
     //do something else 
    } 
}  

*/

// следуйте приведенным ниже код для обработки базового кода construtor. общественного класса BaseClass { общественные BaseClass() { // ничего не делать }

public BaseClass(string sSql) 
    { 
     ExecSQL(sSql); 
     //DO NOT do anything else 
    }  

    public BaseClass(int i, DateTime dt) 
    { 
     //in base class ignore the parameters. 
     string sWhereClause = ""; 
     string sSql = setSQL(sWhereClause); 
     ExecSQL(sWhereClause); 
     //DO NOT do anything else 
    } 

    protected virtual string setSQL(string value) 
    { 
     //set the sql 
     string sSql = ""; 
     //add value into sSql 
     return sSql; 
    } 

    protected virtual void ExecSQL(string sSql) 
    { 
     int i = 1; 
     //execute query    
    } 
} 

public class DerivedClass: BaseClass 
{ 
    //public DerivedClass(string sSql):base (sSql){} 
    public DerivedClass() 
    { 
     //do nothing 
    } 

    public DerivedClass(string sSql) 
    { 
     ExecSQL(sSql); 
     //DO NOT do anything else 
    } 

    public DerivedClass(int i, DateTime dt) 
    { 
     ExecSQL(i, dt); 
     //do something else after base execution 
    } 

    protected void ExecSQL(int i, DateTime dt) //overloaded procedure 
    { 
     string sWhereClause = ""; 
     //construct wherclause based on i, dt 
     string sSql = setSQL(sWhereClause); //calls baseclass function 
     base.ExecSQL(sWhereClause); //calls baseclass procedure 
    }  
} 

DerivedClass MDD = новые DerivedClass (2, DateTime.Now); BaseClass mdB = ​​новый BaseClass ("sql");

Смежные вопросы