Приватный «набор» в C # - возникают проблемы с оборачиванием моего мозга вокруг него - PullRequest
19 голосов
/ 23 июля 2010

Я видел много примеров кода, написанного с использованием чего-то вроде (пожалуйста, прости, как это ужасно консервировано):

public class Test
{
   public object Thingy { get; private set; }
}

К сожалению, такого рода примеры никогда по-настоящему не объясняют, почему установлено 'set'как личное.Итак, мне просто интересно, есть ли хороший, общий пример, который проиллюстрирует мне, почему что-то подобное будет использовано.

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

Ответы [ 9 ]

24 голосов
/ 23 июля 2010

Это будет, если у вас есть свойство, которое вы не хотите, чтобы кто-либо устанавливал, кроме вашего класса. Это может быть удобно с идентификаторами базы данных. Внутренний класс может установить его, но вы бы не хотели, чтобы кто-то еще его изменил. Таким образом, вы можете предоставить им доступ для чтения, но не для записи.

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

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

public class Test
{
   private object thingy;
   public object Thingy
   {
      get { return thingy; }
   }
}

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

Я знаю, что это объяснение было излишним, но в моей голове все время появлялись разные вещи.

9 голосов
/ 23 июля 2010

как простой пример; это дешевый способ создания «достаточно неизменного» объекта (для использования в потоках, состоянии и т. д.). Но также и в любом месте, где клиенту просто не нужно назначать его, или нельзя доверять для его назначения (правильно).

Другим примером может быть список:

public List<Foo> Items {get;private set;}

, поскольку мы могли бы назвать obj.Items.Add() и т. Д., Но мы бы редко присваивали obj.Items = .... Однако этот пример искажен необходимостью явной инициализации в конструкторе, а XmlSerializer ненавидит его - если честно, для списков, которые я в основном использую:

private readonly List<Foo> items = new List<Foo>();
public List<Foo> Items {get { return items;}}

, который решает оба из них.

В качестве другого примера, контрастируем:

private readonly int foo;
public int Foo {get{return foo;}}

против

private readonly int foo;
public int Foo {get{return foo;} private set {foo=value;}}

этот шаблон может быть полезен при сериализации, например, с DataContractSerializer (с добавлением некоторых атрибутов), поскольку многие сериализаторы по-прежнему будут искать частные средства доступа. Это избавляет нас от необходимости украшать наше внутреннее состояние (foo), но дает фанеру конфиденциальности set.

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

4 голосов
/ 23 июля 2010

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

2 голосов
/ 23 июля 2010

Я видел, как это используется с дизайном:

public class whatever
{
    public string WhateverId { get; private set; }

    public static whatever Create(string whateverId)
    {
        return new whatever() { WhateverId = whateverId };
    }
}

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

закрытый набор просто дает простой синтаксис инициализатора, мне это нравится для некоторых сценариев.

Также может использоваться, если он изменчив, но вам нужно управлять им, когда изменения сделаны

public void SetWhateverId(string whateverId)
{
    DisconnectAllCurrentWhateverIdReferences();
    WhateverId = whateverId;
    ReconnectAllPreviousWhateverIdReferences();
}
2 голосов
/ 23 июля 2010

По сути, это свойство только для чтения. Если бы он был написан полностью (не как свойство auto), вы просто не указали бы сеттер.

Два примера, которые в значительной степени совпадают:

class Foo1
{
   public int Id { get; private set; }
   public Foo1()
   {
       Id = lastId ++;
   }
}

class Foo2
{
   private int _id;  // could be readonly 
   public int Id { get { return _id; } }
   public Foo2()
   {
       _id = lastId ++;
   }
}
1 голос
/ 23 июля 2010

приватный набор очень удобен для простых типов неизменяемых значений.

struct Point
{
    public int X { get; private set; }
    public int Y { get; private set; }
    public Point(int x, int y)
    {
        this = default(Point);
        X = x;
        Y = y;
    }
}
1 голос
/ 23 июля 2010

Этот синтаксис позволяет вам предоставлять общедоступное свойство, которое кажется доступным только для чтения пользователям вашего API, но внутренне может изменяться. Благодаря автоматической реализации таким способом вы избегаете необходимости писать шаблонный код, такой как отдельный установщик или вспомогательное поле для значения, и оставляете место в своем проекте, чтобы добавить алгоритм задания на заказ, если в какой-то момент это будет сочтено необходимым будущее без необходимости решать сразу.

0 голосов
/ 23 июля 2010

Чтобы ответить на вопрос о распространенном сценарии, в котором это можно использовать ... В шаблоне MVP, если ваша Модель предоставляет некоторые свойства для вашего докладчика, я бы написал:

public string Bazinga { get; private set; }

Теперь модель можетизменить это значение, но другие классы, которые его используют, не могут.

0 голосов
/ 23 июля 2010

Это просто laziness, полученное из авто-свойств. До появления авто свойств люди реализовывали метод получения и опускали его для свойств, предназначенных только для чтения.

public class Test
{
   private /*readonly*/ Type _thingy;
   public Type Thingy { get { return _thingy; } }
}

Надеюсь, C # 5 позволит вам создавать авто-свойства только с геттером - потому что этого хотят все. (Они должны делать сеттеры только для чтения в auto-props, мне это очень нужно)

...