代码之家  ›  专栏  ›  技术社区  ›  Aaronaught

纯写属性有实际应用吗?

  •  46
  • Aaronaught  · 技术社区  · 16 年前

    在C#-可能还有很多其他语言中,我记得Delphi也允许您这样做-编写以下语法是合法的:

    class WeirdClass
    {
        private void Hello(string name)
        {
            Console.WriteLine("Hello, {0}!", name);
        }
    
        public string Name
        {
            set { Hello(name); }
        }
    }
    

    换句话说,该属性具有 塞特 吸气剂 ,是的 只写 .

    我想我想不出为什么会这样 非法的

    CS83417:属性“Name”似乎完全无用且愚蠢。糟糕的程序员!考虑用方法替换。

    但也许我做这件事的时间还不够长,或者在一个太窄的领域里工作,看不到任何有效使用这种结构的例子。

    是否存在仅写属性的实际示例,这些属性不能被直接的方法调用替代,或者变得不那么直观?

    14 回复  |  直到 6 年前
        1
  •  14
  •   Kaleb Brasee    16 年前

    只写属性实际上非常有用,我经常使用它们。都是关于 encapsulation

    "Why getter and setter methods are evil" 对于这个有趣的讨论。我并不像这篇文章的作者那样对这件事很坚决,但我认为这是一件值得思考的事情。我通常使用setter,但很少使用getter。

        2
  •  16
  •   Ðаn    7 年前

    代码分析(又称FxCop)确实为您提供了诊断:

    CA1044 添加一个具有 大于或等于的可访问性 等于其setter或将其转换为 属性转换为方法。

        3
  •  15
  •   Pang Ajmal PraveeN    5 年前

    我对这个问题的第一个反应是:“那 java.util.Random#setSeed 方法?”

    封装

        4
  •  9
  •   BoltClock    14 年前

    是只写的,它是有用的和(合理的)直观的,并且是可读的属性( 得到

    public class MyGraphicalObject
    {
        public double ScaleX { get; set; }
        public double ScaleY { get; set; }
        public double ScaleZ { get; set; }
    
        public double Scale { set { ScaleX = ScaleY = ScaleZ = value; } }
    
        // more...
    }
    
        5
  •  3
  •   neontapir    12 年前

    假设我上过一节课:

    public class WhizbangService {
        public WhizbangProvider Provider { set; private get; }
    }
    

    WhizbangProvider不打算被外部世界访问。我从来都不想和你交往 service.Provider ,太复杂了。我需要一个像WhizbangService这样的类来充当门面。然而,有了setter,我可以做这样的事情:

    service.Provider = new FireworksShow();
    service.Start();
    

    service.Stop();
    service.Provider = new FountainDisplay(new StringOfLights(), 20, UnitOfTime.Seconds);
    service.Start();
    

    等等

    public abstract class DisplayService {
        public WhizbangProvider Provider { set; private get; }
    }
    
    public class WhizbangService : DisplayService  { }
    

    这里,构造函数注入的替代方案是:

    public abstract class DisplayService {
        public WhizbangProvider Provider;
    
        protected DisplayService(WhizbangProvider provider) {
           Provider = provider ?? new DefaultProvider();
        }
    }
    
    public class WhizbangService : DisplayService  { 
        public WhizbangService(WhizbangProvider provider) 
          : base(provider) 
        { }
    }
    

    在我看来,这种方法比较混乱,因为您需要了解类的一些内部工作,特别是,如果您通过 null 对于构造函数,您将得到一个合理的默认值。

        6
  •  3
  •   AustinWBryan ravenspoint    8 年前

    在MVP模式中,在视图上编写一个带有setter的属性是很常见的(不需要getter)——只要演示者设置了它的内容,该属性就会使用该值来更新一些UI元素。

    看见 here

    public partial class ShowMeTheTime : Page, ICurrentTimeView
    {
        protected void Page_Load(object sender, EventArgs e) 
        {
            CurrentTimePresenter presenter = new CurrentTimePresenter(this);
            presenter.InitView();
        }
    
        public DateTime CurrentTime 
        {
            set { lblCurrentTime.Text = value.ToString(); }
        }
    }
    

    presenter InitView方法仅设置属性的值:

    public void InitView() 
    {
        view.CurrentTime = DateTime.Now;
    }
    
        7
  •  2
  •   user541686    14 年前

    例如,在屏幕上绘图时(这正是桌面窗口管理器在Windows中所做的):
    你当然可以在屏幕上画图,但是你永远不需要读回数据(更不用说期望得到和以前一样的设计了)。

    性质
    用于只写数据而从不读取数据的情况。

        8
  •  2
  •   Peter Cunningham    8 年前

    虽然 .NET design guidelines 建议使用方法(“SetMyWriteOnlyParameter”)而不是只写属性,我发现从序列化表示(从数据库)创建链接对象时,只写属性很有用。

    我们的应用程序代表油田生产系统。我们将系统作为一个整体(“模型”对象)和各种储层、井、节点、组等对象。

    首先创建模型并从数据库中读取-其他对象需要知道它们属于哪个模型。但是,模型需要知道哪个较低的对象代表销售总额。将此信息存储在模型属性中是有意义的。如果我们不想对模型信息进行两次读取,我们需要能够在创建Sales对象之前读取其名称。随后,我们将“SalesObject”变量设置为指向实际对象(例如,用户对该对象名称的任何更改都不会导致问题)

    我们更喜欢使用只写属性“SalesObjectName=”TopNode“”,而不是方法“SetSalesObjectName”(“TopNode”)——因为在我们看来,后者表明SalesObject存在。

    这是一个小问题,但足以让我们想要使用只写属性。

        9
  •  1
  •   Jonathan Allen    16 年前

    就我而言,他们没有。每次我使用一个只写属性作为快速攻击,我后来都会后悔。通常我会得到一个构造函数或一个完整的属性。

    当然,我想证明一个否定的观点,所以也许我遗漏了一些东西。

        10
  •  1
  •   Skip Saillors    12 年前

    我想构造一个C#属性,该属性派生自ASP.NET MVC应用程序的AuthorizeAttribute。如果用户返回的信息是授权的,我会说是授权的。构造函数注入不起作用,因为

    public AllowedAttribute: AuthorizeAttribute
    {
        public AllowedAttribute(IStore store) {...}
        private IStore Store { get; set; }
        ...
    }
    

    使存储成为位置属性参数,但IStore不是有效的属性参数类型,并且编译器不会生成带注释的代码。我不得不依靠财产设定者的注入。

    public AllowedAttribute: AuthorizeAttribute
    {
        [Inject] public IStore Store { private get; set; }
        ...
    }
    

    除了属性Setter而不是构造函数注入的所有其他缺点外,该服务是一个只写属性。我不需要对setter的实现有足够详细的了解,就可以让客户机知道这一点。让客户也看到成功者对任何人都没有好处。

        11
  •  0
  •   BoltClock    14 年前

    不,我无法想象他们在什么情况下 不能 被替换,虽然可能有人认为他们更可读。

    假设情况:

    CommunicationDevice.Response = "Hello, World" 
    

    而不是

    CommunicationDevice.SendResponse("Hello, World")
    

    有趣的是,VB.NET甚至为这种奇怪的属性设置了自己的关键字;)

    Public WriteOnly Property Foo() As Integer
       Set(value As Integer)
         ' ... '
       End Set
    End Property
    

    尽管许多来自外部的“只写”属性实际上有一个私有getter。

        12
  •  0
  •   Tanner Swett    11 年前

    我最近开发了一个处理密码的应用程序(请注意,我并不是说以下是一个好主意;我只是在描述我所做的。)

    我上了一节课, HashingPassword 哈希密码 对象

    于是我有了另一个物体,我不记得它是什么;让我们假设它是一个密码保护的香蕉。这个 Banana Password ,它创建了一个 并将其存储在的私有属性中 香蕉 password 属性 哈希密码 是私有的,无法为此属性编写getter。

    那么,为什么我有一个只包含集合的属性,名为 而不是调用方法 SetPassword ? 因为这是有道理的。实际上,其效果是设置 ,如果我想设置 香蕉 对象,我希望通过设置属性而不是调用方法来实现。

    使用名为 设置密码 不会有任何大的缺点。但我也没有看到任何明显的优势。

        13
  •  0
  •   z00l    10 年前

    我知道这已经存在很长一段时间了,但我遇到了它,并且有一个有效的(imho)用例:

    当您从ajax向webapi调用发布参数时,您可以简单地尝试填写参数类的属性并包括验证或其他内容。

    public int MyFancyWepapiMethod([FromBody]CallParams p) {
        return p.MyIntPropertyForAjax.HasValue ? p.MyIntPropertyForAjax.Value : 42;
    }
    
    public class CallParams
    {
        public int? MyIntPropertyForAjax;
    
        public object TryMyIntPropertyForAjax
        {
            set
            {
                try { MyIntPropertyForAjax = Convert.ToInt32(value); }
                catch { MyIntPropertyForAjax = null; }
            }
        }
    }
    

    在JavaScript端,您只需填写参数,包括验证:

    var callparameter = {
        TryMyIntPropertyForAjax = 23
    }
    

        14
  •  0
  •   Roberto Gueleri    5 年前

    我在编写从JSON数据库(Firebase)读取数据的程序时遇到了这种情况。它使用Newtonsoft的Json.NET来填充对象。一旦加载,数据就不会改变。此外,对象仅被反序列化,不会再次序列化。也许有更好的方法,但这个解决方案对我来说似乎是合理的。

    using Newtonsoft.Json;
    // ...
    
    public class SomeDatabaseClass
    {
        // JSON object contains a date-time field as string
        [JsonProperty("expiration")]
        public string ExpirationString
        {
            set
            {
                // Needs a custom parser to handle special date-time formats
                Expiration = Resources.CustomParseDateTime(value);
            }
        }
        
        // But this is what the program will effectively use.
        // DateTime.MaxValue is just a default value
        [JsonIgnore]
        public DateTime Expiration { get; private set; } = DateTime.MaxValue;
        
        // ...
    }
    
        15
  •  -1
  •   BoltClock    14 年前

    好吧,从技术上讲,只有Setter属性本身并没有什么问题。Setter可以进行一些验证,也许其他一些方法(public或private)也可以依赖它。

    class SomeClass {
        private int _someVar;
    
        SomeClass(int someVar) {
            if(someVar > 0) _someVar = someVar;
        }
    
        public int SomeVar {
            set { if(value > 0) _someVar = value; }
        }
    
         public string SomeFunction(){
           return "This is an important function that uses _someVar " + _someVar;
         }
    }
    

    因此,声明本身可能合法有效。虽然您的方法体是一个巨大的代码气味,但这不是编译器要关心的工作。