Как ведут себя различные реализации статических свойств только для чтения (vs полей) в C#?

#c# #.net #optimization #language-lawyer

Вопрос:

Хотел задать пару вопросов о том, как платформа .NET обрабатывает статические переменные во время выполнения в своей внутренней работе.

Примечание: Это сделано в образовательных целях, а не из-за проблем с производительностью.

Учитывая три приведенных ниже определения переменных:

 using System;

public static class UserProperties
{
    public static Guid UserId1 { get { return new Guid("00000000-0000-0000-0000-000000000001"); } }

    public static Guid UserId2 { get; } = Guid.Parse("00000000-0000-0000-0000-000000000001");

    public static readonly Guid UserId3 = Guid.Parse("00000000-0000-0000-0000-000000000001");
}
 

Во-первых: насколько я понимаю, в использовании UserId2 over есть преимущество UserId1 , поскольку он не создает новый Guid экземпляр при каждом доступе к свойству, а вместо этого присваивает один экземпляр резервному полю, которое поддерживается до тех пор, пока программа запущена. Правильно ли это понимание?

Во-вторых: Есть ли какая-то польза в использовании UserId3 сверх UserId2 ? Я подозреваю, что так оно и будет, поскольку первое само по себе является полем, а второе-это свойство auto, которое, как я думаю, вызывает метод каждый раз, когда на него ссылаются, но я не уверен в этом.

И последнее: если действительно существуют различия (которые, да, незначительны в данном конкретном примере, но все же), являются ли они несуществующими в результате оптимизации, т. Е. Выдает ли компилятор или JIT одни и те же инструкции?

Спасибо!

Комментарии:

1. p.s. Не смог придумать лучшего названия; любой может предложить свои предложения.

2. Ваше понимание выглядит правильным. Что касается оптимизации — первая не может быть сведена к остальным, так как она возвращает новый экземпляр Guid при каждом вызове. Однако второй, скорее всего, будет встроен JIT-компилятором (на каждом сайте вызовов), чтобы быть таким же, как третий. Самое важное различие между 2 и 3 заключается в том, что 2 позволяет позже изменять логику геттера, не нарушая (сторонний) код, используя его. На 3 нет «геттера», поэтому это невозможно сделать, не перейдя с поля на свойство (разрывное изменение).

3. В сборке выпуска UserId2 будет встроен в то же, UserId3 что и так, без разницы

4. Почему бы не сравнить яблоки с яблоками и не сделать return Guid.Parse(); ?