我的经理问我,使用带有setter的属性是否是一个好习惯,但是没有getter。
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; }
}
}
他将使用其他属性公开来自私有字段的属性,由此setter设置。
我的建议是只使用私有字段并在构造函数中设置它,在这种情况下可以正常工作。如果我需要首先构建一个构造对象(甚至可能使用多态),我仍然会更喜欢Load
方法,而不是无吸收属性。
但我很感兴趣。我们都非常关注最佳实践,并尝试确保我们的代码是标准化的。有没有人有关于无吸气剂属性的官方文章?或者更好 - 在.NET Framework本身中这种用法的一个例子?
答案 0 :(得分:17)
官方文章: Design Guidelines for Developing Class Libraries - > Member Design Guidelines - > Property Design
不提供仅限设置的属性。
如果无法提供属性getter,请使用方法实现 相反的功能。方法名称应以Set开头 其次是属性名称。例如, AppDomain有一个名为SetCachePath的方法,而不是一个 set-only属性,名为CachePath。
答案 1 :(得分:9)
考虑到问题是:有没有人有关于无吸气剂属性的官方文章?或者更好 - 在.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 = neutral,PublicKeyToken = b77a5c561934e089;类型:FileIOAccess;属性:PathDiscovery
汇编:mscorlib,Version = 4.0.0.0,Culture = neutral,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
答案 2 :(得分:3)
我没有官方文章或例子......只有意见。
在我看来,一个无法读取的财产是一种愤怒和混淆的野兽。
归结为意图。一个房产说“我打算让消费者读我,甚至可能写信给我”。名为“SetSomeAttribute”的函数声明了一个只写意图。
还有整体,我的数据,所以为什么我不能把它读回去。
所以在我看来,使用只写属性是没有充分理由的。
答案 3 :(得分:2)
拥有一个没有getter的属性是没有错的,如果这是使你的代码最易理解和可维护的。但是,这方面的好例子可能非常罕见。
我曾经使用过getter-less属性的最好的东西是单元测试类,其属性具有无法访问的setter。例如:
public class MyClass
{
public int MyId { get; protected set; }
}
public class MyClass_Test : MyClass
{
public int MyId_Set
{
set { MyId = value; }
}
}
这样我可以在单元测试中使用MyClass_Test
并预设一个值MyId
,并能够对特定方法进行单元测试。
另外,在直接回复您的示例时,使用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; }
}
}
答案 4 :(得分:0)
没有什么可说的,你不能这样做,但看起来确实有点奇怪。我会有一个私人财产和一种设定它的方法,即
private string _test;
public void SetTest(string test)
{
_test = test;
}
答案 5 :(得分:0)
你必须记住为什么存在属性。它们取代了以下模式
class Foo
{
private Bar _bar;
public Bar GetBar()
{
return _bar;
}
public void SetBar(Bar bar)
{
_bar = bar;
}
}
虽然拥有一个没有Setter的属性看起来很奇怪,但我认为没有Get方法的Set方法看起来很奇怪。
事实上,我很确定属性是语法糖并被重写为get / set方法。或者至少非常接近。
答案 6 :(得分:0)
当由于某种原因,构造函数和方法注入都不适合您时,它们可能会用于依赖注入。
但我无法想象这样的情况。
答案 7 :(得分:0)
嗯,它们可以很好地用于对象初始化器中的私有字段:
var obj = new MyClass
{
Prop1 = value1,
Prop2 = value2
};
这可能是将它们作为构造函数参数编写的另一种方法:
var obj = new MyClass(value1, value2);
但如果有许多(可选)参数,则只能使用writeonly属性。
答案 8 :(得分:0)
正如已经提出的那样,我认为答案是在问题的背景下最有意义的答案。我可以想到只有一个setter属性的两种选择,这可能值得一试,看看哪个是最有意义的:
答案 9 :(得分:-3)
您可以拥有更整洁的属性,并且可以在其上执行完全访问控制,而不会使用凌乱的_localVariable和属性语法。
示例:
/// <summary>
/// Publicly readable, privately settable.
/// </summary>
public int FirstProperty { get; private set; }
/// <summary>
/// Entirely private
/// </summary>
private int SecondProperty { get; set; }