В чем разница между возвратом значения внутри get и назначением свойства? - PullRequest
2 голосов
/ 02 мая 2020

Если бы я хотел сохранить это под рукой для не асинхронных c методов, которые возвращают задачу.

public static Task CompletedTaskA { get { return Task.CompletedTask; } }

public static Task CompletedTaskB { get; } = Task.CompletedTask;

Должно ли одно быть предпочтительным по сравнению с другим для какого-либо контекста? Или они одинаковые? Я также удивляюсь тому же со строками и в основном всем, что я делаю со свойствами ie:

get {return "some string"; } против { get; } = "some string";

РЕДАКТИРОВАТЬ: Я хотел бы уточнить мое использование выше проп , У меня есть несколько обработчиков событий, у которых есть Task в качестве возвращаемого типа, предложенный мне библиотекой, которую я использую. пример одного такого события:

private Task Client_MessageReceived(Message message)
{
   Task.Run(async ()=> await HandleMessageReceived(message));

   // here is where i would use it
   return CompletedTask; // A OR B?
}

private async Task HandleMessageReceived(Message message)
{
   // Do stuff with message that might take long and block the handler
}

Мое намерение состоит в том, чтобы сохранить выполненное задание в поле (в данном случае я выбираю свойство только для чтения) и просто использовать его для удовлетворения возврата задания. Мне интересно, продолжает ли один из приведенных выше примеров использовать одно и то же завершенное задание, а другой продолжает каждый раз запрашивать еще одно выполненное задание?

Ответы [ 3 ]

1 голос
/ 02 мая 2020

Если вы go до SharpLab и посмотрите на код:

public class C 
{
    public void M() 
    {
    }

    public string Greetig_1
    {
        get{return "hello";}
    }

    public string Greeting_2{get;} = "hello";
}

Вы видите, что Greeting_2 поддерживается переменной-членом:

public class C
{
    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private readonly string <Greeting_2>k__BackingField = "hello";

    public string Greeting_1
    {
        get
        {
            return "hello";
        }
    }

    public string Greeting_2
    {
        [CompilerGenerated]
        get
        {
            return <Greeting_2>k__BackingField;
        }
    }

    public void M()
    {
    }
}

Это соответствует уровню IL. Поскольку Greeting_2 поддерживается переменной-членом, эта переменная инициализируется в конструкторе.

В вашем примере с Task.CompletedTask вы получите:

public static Task CompletedTaskB { get; } = Task.CompletedTask;

Кэширование Task, тогда как:

public static Task CompletedTaskA { get { return Task.CompletedTask; } }

Сделайте вызов, чтобы получить CompletedTask объект в Task каждый раз. В действительности это будет встроено JIT. Преимущество этого подхода заключается в том, что он не добавляет в ваш класс дополнительную (скрытую) переменную-член, что может быть проблемой, если у вас много экземпляров и вас беспокоит использование памяти.

1 голос
/ 02 мая 2020

Они не одинаковы. Метод get свойств вызывается каждый раз, когда вы получаете к нему доступ. По умолчанию, когда вы создаете свойство, за ним будет скрытое поле, поэтому:

public static Task CompletedTaskB { get; set; }

фактически сгенерирует это за кадром:

private static Task _completedTaskB;
public static Task CompletedTaskB 
{
 get {
  return _completedTaskB;
 } 
 set {
  _completedTaskB = value;
 } 
}

Когда вы назначите свойство = Task.CompletedTask, вы устанавливаете его начальное значение, которое эквивалентно:

_completedTaskB = Task.CompletedTask;

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

Я заметил, что вы определяем это как только для чтения (только получатель, а не установщик), поэтому вы не сможете назначить переменную. Вместо этого вам придется использовать:

public static Task CompletedTaskA { get { return Task.CompletedTask; } }

Это будет возвращать Task.CompletedTask все время.

В общем, разница между:

{ get; set; } = "some string";

и

get {return "some string"; }

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

0 голосов
/ 02 мая 2020

Когда вы присваиваете значение свойству прямо в определении, за кулисами происходит какое-то «волшебство» c. Компилятор создает скрытое вспомогательное поле, и значение присваивается этому вспомогательному полю в конструкторе класса.

Другими словами, вы можете считать, что два приведенных ниже класса работают одинаково.

class AssignedImplicit {
  public string Prop {get;} = "example";
}
class AssignedExplicit {
  private readonly string Prop_BackingField;
  public AssignedExplicit() {
      Prop_BackingField = "example";
  }
  public string Prop { get { return Prop_BackingField; } }
}

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

Это верно для строк или для любого другого типа. , Если вы присваиваете значение свойству, работа по созданию / извлечению этого значения помещается в конструктор вашего класса. Если вы создаете значение в методе get, то работа помещается в метод get.

...