public module Program
{
Main() : void
{
def x = First();
Console.WriteLine($"$x");
}
public class Base
{
}
public class First : Base
{
field : Second = Second(this);
}
public class Second
{
field : First;
internal this(first : First)
{
field = first;
}
}
}
Ошибка компилятора:
``this'' or ``base'' usage before base is constructed
Если мы чуть изменим код:
public module Program
{
Main() : void
{
def x = First();
Console.WriteLine($"$x");
}
public class Base
{
}
public class First : Base
{
field : Second = Second(() => this);
}
public class Second
{
field : First;
internal this(first : void -> First)
{
field = first();
}
}
}
Все работает без проблем. Хотя лямбда, по идее, должна вызываться тогда же, когда в первом примере передается this, то есть опять до конструирования базового класса.
В C# аналоги обоих примеров не компилируются:
Keyword 'this' is not available in the current context
В чем тут магия?
На такое поведение компилятора можно полагаться, или это баг, который может быть исправлен?
Здравствуйте, catbert, Вы писали:
C>Все работает без проблем. Хотя лямбда, по идее, должна вызываться тогда же, когда в первом примере передается this, то есть опять до конструирования базового класса.
C>В C# аналоги обоих примеров не компилируются: C>
Keyword 'this' is not available in the current context
C>В чем тут магия?
C>На такое поведение компилятора можно полагаться, или это баг, который может быть исправлен?
Корректное поведение — поведение компилятора C#-а, т.к. рабочий вариант в nemerle (с лямбдой) позволяет обратиться из внешнего кода к недоконструированному объекту.
Здравствуйте, Tissot, Вы писали:
T>Корректное поведение — поведение компилятора C#-а, т.к. рабочий вариант в nemerle (с лямбдой) позволяет обратиться из внешнего кода к недоконструированному объекту.
На самом деле, C# тоже позволяет обратиться из внешнего кода к недоконструированному объекту:
class First
{
Second field;
public First()
{
field = new Second(this);
}
}
class Second
{
First field;
public Second(First x)
{
DoEveryPossibleThingWith(x)
}
}
Насколько я понимаю, разница в том, позволять ли доступ к объекту до вызова конструктора базового класса.
Здравствуйте, catbert, Вы писали:
T>>Корректное поведение — поведение компилятора C#-а, т.к. рабочий вариант в nemerle (с лямбдой) позволяет обратиться из внешнего кода к недоконструированному объекту.
C>На самом деле, C# тоже позволяет обратиться из внешнего кода к недоконструированному объекту:
C>Насколько я понимаю, разница в том, позволять ли доступ к объекту до вызова конструктора базового класса.
Это уже ответственность автора этого класса. В изначальном варианте насколько я понимаю, не вызывается конструктор базового класса.
Здравствуйте, BogdanMart, Вы писали:
BM>Здравствуйте, Tissot, Вы писали:
BM>Не знал, что поля инициализируються до вызова базового конструктора (а толку от этого?)
В спецификации C# так написано:
This ordering ensures that all instance fields are initialized by their variable initializers before any statements that have access to that instance are executed.
Мне кажется, в инициализаторах должно быть возможно все, что возможно в самом конструкторе. Поэтому base() должен вызываться самым первым (хотя тогда возникают нюансы типа this() { base(myField); }).
Судя по тому, как все сделано в Немерле, возможность использовать this в лямбде-инициализаторе — баг. Но довольно полезный баг.