Подтвердить что ты не робот

Есть ли причина иметь свойство без геттера?

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

public class PropertyWrapper
{   
    private MyClass _field;

    public MyClass Property
    {
        set { _field = value; } 
    }

    public string FirstProperty
    {
        get { return _field.FirstProperty; } 
    }

    public string SecondProperty
    {
        get { return _field.SecondProperty; } 
    }
}

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

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

Но меня это интересует. Мы оба очень обеспокоены лучшими практиками и стараемся, чтобы наш код был стандартизован. У кого-нибудь есть официальные статьи о свойствах без геттера? Или еще лучше - пример этого использования в самой .NET Framework?

4b9b3361

Ответ 1

Официальная статья: Рекомендации по разработке для разработки библиотек классовРуководство по дизайну элементовДизайн недвижимости

Не предоставлять свойства только для установки.

Если свойство getter невозможно предоставить, используйте метод для реализации вместо этого. Имя метода должно начинаться с Set за которым следует имя свойства. Например, У AppDomain есть метод, называемый SetCachePath, вместо того, чтобы иметь свойство set-only, называемое CachePath.

Ответ 2

Принимая во внимание следующие вопросы: есть ли у кого-нибудь официальные статьи о свойствах без геттера? Или еще лучше - пример этого использования в самой .NET Framework? а не о мнении; Я написал приложение для быстрого тестирования, чтобы прочитать все свойства всех типов всех сборок, загруженных в консольное приложение по умолчанию:

foreach (var assem in AppDomain.CurrentDomain.GetAssemblies())
{
    foreach (var type in assem.GetTypes())
    {
        foreach (var prop in type.GetProperties())
        {
            if (!prop.CanRead)
                Console.WriteLine("Assembly: {0}; Type: {1}; Property: {2}", assem.FullName, type.Name, prop.Name);
        }
    }
}

Результаты:

Сборка: mscorlib, Version = 4.0.0.0, Culture = нейтральная, PublicKeyToken = b77a5c561934e089; Тип: FileIOAccess; Свойство: PathDiscovery

Сборка: mscorlib, Version = 4.0.0.0, Culture = нейтральная, PublicKeyToken = b77a5c561934e089; Тип: RedirectionProxy; Свойство: ObjectMode

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

ИЗМЕНИТЬ

Интересно, что запуск одного и того же кода с прикрепленным отладчиком дает гораздо больше результатов:

Assembly: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: FileIOAccess; Property: PathDiscovery
Assembly: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: RedirectionProxy; Property: ObjectMode
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: AxHost; Property: Site
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DataGridTextBoxColumn; Property: PropertyDescriptor
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DisplayedBandsData; Property: FirstDisplayedFrozenCol
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DisplayedBandsData; Property: FirstDisplayedFrozenRow
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DisplayedBandsData; Property: LastDisplayedFrozenCol
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DisplayedBandsData; Property: LastDisplayedFrozenRow
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DisplayedBandsData; Property: LastDisplayedScrollingRow
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ErrorProvider; Property: Site
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: WebBrowserBase; Property: Site
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: WebBrowser; Property: Site
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DropDownButton; Property: UseComboBoxTheme
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: GridErrorDlg; Property: Details
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: GridErrorDlg; Property: Message
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DropDownHolder; Property: ResizeUp
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: GridViewEdit; Property: DontFocus
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: GridViewEdit; Property: DisableMouseHook
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: MouseHook; Property: DisableMouseHook
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ManifestSignedXml; Property: Resolver
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ContainerProxy; Property: Bounds
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: RightToLeftProxy; Property: Bounds
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: TopDownProxy; Property: Bounds
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: BottomUpProxy; Property: Bounds
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ElementProxy; Property: Bounds
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: VerticalElementProxy; Property: Bounds
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: IconComparer; Property: SortOrder
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: MultiPropertyDescriptorGridEntry; Property: PropertyValue
Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ConfigXmlDocument; Property: XmlResolver
Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ConfigXmlDocument; Property: InnerText
Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ProcessThread; Property: IdealProcessor
Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ProcessThread; Property: ProcessorAffinity
Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ConfigXmlAttribute; Property: InnerText
Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ConfigXmlAttribute; Property: InnerXml
Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: AnonymousPipeServerStream; Property: ReadMode
Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: AnonymousPipeClientStream; Property: ReadMode
Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ManifestSignedXml; Property: Resolver
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlResolver; Property: Credentials
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlNullResolver; Property: Credentials
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlSecureResolver; Property: Credentials
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlUrlResolver; Property: Credentials
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlUrlResolver; Property: Proxy
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlUrlResolver; Property: CachePolicy
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlReaderSettings; Property: XmlResolver
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlTextReader; Property: XmlResolver
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlValidatingReader; Property: XmlResolver
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DocumentXmlWriter; Property: NamespaceManager
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DocumentXmlWriter; Property: Navigator
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DocumentXmlWriter; Property: EndNode
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlAttribute; Property: InnerText
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlAttribute; Property: InnerXml
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlDocument; Property: XmlResolver
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlDocument; Property: InnerText
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlUnspecifiedAttribute; Property: InnerText
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlUnspecifiedAttribute; Property: InnerXml
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlPreloadedResolver; Property: Credentials
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XslTransform; Property: XmlResolver
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlSchemaSet; Property: XmlResolver
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlSchemaValidator; Property: XmlResolver
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XsdValidator; Property: Context

Ответ 3

У меня нет официальных статей или примеров.. только мнение.

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

Это сводится к намерениям. В собственности говорится: "Я намерен разрешить потребителю прочитать меня и, возможно, даже написать мне". Функция с именем "SetSomeAttribute" объявляет намерение только для записи.

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

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

Ответ 4

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

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

public class MyClass
{
    public int MyId { get; protected set; }
}

public class MyClass_Test : MyClass
{
    public int MyId_Set
    {
        set { MyId = value; }
    }
}

Таким образом, я могу использовать MyClass_Test в unit test и предварительно установить значение MyId с возможностью unit test определенного метода.

Кроме того, в ответ на ваш пример использование private get, вероятно, будет лучшим способом:

public class PropertyWrapper
{       
    public MyClass Property { private get; set; }

    public string FirstProperty
    {
        get { return Property.FirstProperty; } 
    }

    public string SecondProperty
    {
        get { return Property.SecondProperty; } 
    }
}

Ответ 5

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

    private string _test;

public void SetTest(string test)
{
 _test = test;
}

Ответ 6

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

class Foo
{
     private Bar _bar;

     public Bar GetBar() 
     { 
         return _bar; 
     }

     public void SetBar(Bar bar) 
     { 
         _bar = bar; 
     }
}

Хотя свойство с сеттером выглядит странно для меня, я не думаю, что наличие метода Set без метода Get вообще выглядит нечетным.

На самом деле, я уверен, что свойства являются синтаксическим сахаром и переписываются как методы get/set. Или, по крайней мере, очень близко.

Ответ 7

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

Но я не могу представить такой случай.

Ответ 8

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

var obj = new MyClass
{
    Prop1 = value1,
    Prop2 = value2
};

который может быть альтернативным способом просто написать их как параметры конструктора:

var obj = new MyClass(value1, value2);

Но если есть много (необязательных) параметров, могут быть удобны свойства writeonly.

Ответ 9

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

  • Определите отдельный метод, который принимает единственный параметр.
  • Определите получателя, который всегда возвращает одно и то же значение (например, null). Это зависит от контекста.

Ответ 10

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

Примеры

:

    /// <summary>
    /// Publicly readable, privately settable.
    /// </summary>
    public int FirstProperty { get; private set; }

    /// <summary>
    /// Entirely private
    /// </summary>
    private int SecondProperty { get; set; }