C# Object Initializer - ссылка на новый экземпляр
Можно ли как-то получить ссылку на экземпляр, который я создаю с помощью инициализатора объекта?
var x = new TestClass
{
Id = 1,
SomeProperty = SomeMethod(this)
}
"this" должно указывать на новый экземпляр TestClass, который я создаю. Но это, очевидно, относится к экземпляру класса, в котором находится этот код.
Я не спрашиваю, является ли это хорошим способом сделать это. Я знаю, что я могу сделать это так:
var x = new TestClass {Id= x};
x.SomeProperty = SomeMethod(this);
У меня сложный сценарий, в котором ссылка на новый экземпляр в инициализаторе объекта облегчит жизнь.
Возможно ли это каким-либо образом?
4 ответа
Нет никакого способа обойти это, спецификация C# прямо говорит, что "инициализатор объекта или коллекции не может ссылаться на инициализируемый экземпляр объекта".
Что касается того, почему это невозможно, я подозреваю, что просто нет хорошего способа реализовать это. Нам нужен синтаксический сахар, эквивалентный
var temp = new TestClass();
temp.Id = 1;
temp.SomeProperty = SomeMethod(temp);
x = temp;
Нам просто нужно ключевое слово для ссылки на temp
в инициализаторе, но ни один не легко доступен. Мы не можем использовать this
потому что это уже означает что-то вне инициализатора. Должен SomeProperty = this.SomeMethod(this)
быть эквивалентным temp.SomeProperty = this.SomeMethod(temp)
или же temp.SomeProperty = temp.SomeMethod(temp)
? Второе непротиворечиво, но что произойдет, если нам понадобится первое?
Мы могли бы попытаться использовать x
, хотя мы можем выбрать имя, только если новый объект сразу назначен переменной. Однако теперь мы не можем ссылаться на старое значение x
внутри инициализатора, делая эквивалент temp.SomeProperty = SomeMethod(x)
,
Мы могли бы использовать value
ключевое слово от установщиков свойств. Это звучит хорошо, так как value
уже заменяет отсутствующий параметр, если вы считаете, что свойство get является синтаксическим сахаром для set_SomeProperty(value)
метод. Использование его для ссылки на отсутствующую переменную в инициализаторе объекта выглядит многообещающе. Тем не менее, мы могли бы создать этот объект внутри установщика свойств, в этом случае value
уже используется, и мы должны быть в состоянии сделать temp.SomeProperty = SomeMethod(value)
,
Похоже, нам нужно создать новое ключевое слово только для этой цели, может быть, newthis
, Тем не менее, это серьезное изменение в языке, потому что любой код, который имеет переменную с именем newthis
больше не работает Microsoft, как правило, нужна действительно веская причина для внесения критических изменений, поэтому лучше запретить доступ к инициализируемому объекту.
Нет, вы не можете использовать инициализатор объекта, чтобы назначить объект, который вы создаете где-то еще, - который побеждает весь смысл инициализатора объекта. x
Переменная не присваивается, пока не завершится инициализация объекта. Вам нужно будет присвоить объект, а затем использовать его в отдельной инструкции.
var x = new TestClass {
Id = 1
};
x.SomeProperty = SomeMethod(x);
Экспонировать или использовать объект, который не был полностью построен, обычно очень плохая идея. Учтите следующее:
class Connection
{
internal string connectionString;
public Connection(ConnectionPool pool, string connectionString) {
this.pool = pool;
//this.connectionString = connectionString; // I moved it because I could.
this.pool.Register(this);
this.connectionString = connectionString;
this.Init();
}
private void Init() { //blah }
}
class ConnectionPool
{
public void Register(Connection c)
{
if ( this.connStrings.Contains( c.connectionString ) ) // BOOM
}
}
Это чрезвычайно надуманный пример. Все может стать намного хуже, чем это. Следующее было довольно интересной ссылкой относительно этой проблемы: Частично построенные объекты
var x = new TestClass
{
Id = 1,
SomeProperty = SomeMethod(this)
}
До того, как правая часть этой инициализации будет оценена и выполнена, ссылка на новый объект еще не сделана доступной для кода. Это делается в целях безопасности, в противном случае вы можете создать некоторый тупик или бесконечный цикл с вашим кодом.