Информация об изменениях

Сообщение Re: Идея для новой версии C# от 23.12.2025 12:14

Изменено 23.12.2025 12:24 _FRED_

Re: Идея для новой версии C#
Здравствуйте, VladD2, Вы писали:

VD>Рефачу сейчас библиотеку, в которой создается огромный граф. Перевожу его на поддержку #nullable enable.

VD>И понимаю, что современная поддержка nullable в C# очень неполноценная. Большинство ссылок в законченном графе не нулабельные, но код его построения императивный и в нем просто невозможно без хаков проинициализировать свойства во время создания объектов. Приходится прибегать к вот такому хаку:
VD>var obj1 = new SomeType1() { Prop1 = null! };
VD>var obj2 = new SomeType2() { Prop1 = obj1 };

VD>obj1.Prop1 = obj2;


Можешь показать, как Prop1 и Prop2 объявлены? По идее уже в их объявлении у тебя может быть засада с
public SomeType2 Prop { get; set; } = null!;


VD>Вот собственно стало очевидно, что система нулабельности для этого не приспособлена.

VD>Предлагаю расширить C# блоком инициализации, внутри которого не будет проверяться нулабельность, а все проверки будут осуществляться при выходе из него:
VD>init (var obj1 = new SomeType1()) // не ругается на то, что obj1.Prop1 не заполнен
VD>…


А #nullable disable и #nullable restore (здесь) не подходят?
#nullable disable

var obj1 = new SomeType1 { Prop = null, }; // No warning here
var obj2 = new SomeType2 { Prop = obj1, };

obj1.Prop = obj2;

#nullable restore

obj1.Prop = GetNullable(); // CS8601 Possible null reference assignment.

static SomeType2? GetNullable() => null;

file sealed class SomeType1 { public SomeType2 Prop { get; set; } = null!; };
file sealed class SomeType2 { public SomeType1 Prop { get; set; } = null!; };
Re: Идея для новой версии C#
Здравствуйте, VladD2, Вы писали:

VD>Рефачу сейчас библиотеку, в которой создается огромный граф. Перевожу его на поддержку #nullable enable.

VD>И понимаю, что современная поддержка nullable в C# очень неполноценная. Большинство ссылок в законченном графе не нулабельные, но код его построения императивный и в нем просто невозможно без хаков проинициализировать свойства во время создания объектов. Приходится прибегать к вот такому хаку:
VD>var obj1 = new SomeType1() { Prop1 = null! };
VD>var obj2 = new SomeType2() { Prop1 = obj1 };

VD>obj1.Prop1 = obj2;


Можешь показать, как Prop1 и Prop2 объявлены? По идее уже в их объявлении у тебя может быть засада с
public SomeType2 Prop { get; set; } = null!;


VD>Вот собственно стало очевидно, что система нулабельности для этого не приспособлена.

VD>Предлагаю расширить C# блоком инициализации, внутри которого не будет проверяться нулабельность, а все проверки будут осуществляться при выходе из него:
VD>init (var obj1 = new SomeType1()) // не ругается на то, что obj1.Prop1 не заполнен
VD>…


А #nullable disable и #nullable restore (здесь) не подходят?
#nullable disable

var obj1 = new SomeType1 { Prop = null, }; // No warning here
var obj2 = new SomeType2 { Prop = obj1, };

obj1.Prop = obj2;

#nullable restore

obj1.Prop = GetNullable(); // CS8601 Possible null reference assignment.

static SomeType2? GetNullable() => null;

file sealed class SomeType1 { public SomeType2 Prop { get; set; } = null!; };
file sealed class SomeType2 { public SomeType1 Prop { get; set; } = null!; };


По идее вся засада в том, как объявить подобное свойство, которое должно быть проинициализированно после конструктора / инициализатора?

Я бы попробовал отказаться от null-ов как-то так:
file sealed class SomeType1
{
  public SomeType1() { }

  private SomeType1(bool uninitialized) {
    Debug.Assert(uninitialized);
  }

  internal static SomeType1 Uninitialized { get; } = new SomeType1(uninitialized: true);

  public SomeType2 Prop { get; set; } = SomeType2.Uninitialized;

  public void PostInitialization() {
    if(Prop == SomeType2.Uninitialized) {
      throw new InvalidOperationException();
    }//if
  }
};

file sealed class SomeType2
{
  public SomeType2() { }

  private SomeType2(bool uninitialized) {
    Debug.Assert(uninitialized);
  }

  internal static SomeType2 Uninitialized { get; } = new SomeType2(uninitialized: true);

  public SomeType1 Prop { get; set; } = SomeType1.Uninitialized;

  public void PostInitialization() {
    if(Prop == SomeType1.Uninitialized) {
      throw new InvalidOperationException();
    }//if
  }
};