Всем известна функция C#, когда нам не нужно инициализировать каждое свойство объекта отдельно, а просто прописать его в конструкторе.

var obj2 = new Class1("a");
obj2.S = string.Empty;

такой же, как

var obj2 = new Class1("a") {S = string.Empty};

Даже ReSharper так считает:

Но это не просто синтаксический сахар, и это не одно и то же.

Давайте представим пример описания Class1 следующим образом:

public class Class1
{
      public string Prop;
      public Class1(string s)
      {
           Prop = s;
      }
      public string S
      {
          set => throw new Exception();
      }
}

Итак, установка свойства S в строку. Пустое значение вызовет исключение. В этом случае мы можем увидеть разницу между встроенной инициализацией и явной инициализацией.

Когда мы вызываем конструктор и только после его инициализации, объект не является нулевым, а в случае встроенной инициализации мы имеем нулевой объект.

Если мы посмотрим на IL-код, то увидим разницу в реализации:

Явная инициализация:

IL_0002:  ldstr      "a"
    IL_0007:  newobj     instance void ConsoleApp2.Class1::.ctor(string)
    IL_000c:  stloc.0
    IL_000d:  ldloc.0
    IL_000e:  ldsfld     string [System.Runtime]System.String::Empty

Встроенная инициализация:

IL_0002:  ldstr      "a"
    IL_0007:  newobj     instance void ConsoleApp2.Class1::.ctor(string)
    IL_000c:  dup
    IL_000d:  ldsfld     string [System.Runtime]System.String::Empty
    IL_0012:  callvirt   instance void ConsoleApp2.Class1::set_S(string)
    IL_0017:  nop
    IL_0018:  stloc.0

Здесь главное, где находится инструкция stloc.0 (Поместить значение из стека в локальную переменную 0). В случае встроенной инициализации новый объект Class1 создается и помещается в стек, но не перемещается в локальную переменную из-за исключения в инструкции IL_0012.