【问题标题】:What is the purpose of set { return; }?set { return; 的目的是什么? }?
【发布时间】:2017-02-16 20:35:50
【问题描述】:

我在各个地方都看到过以下代码:

 namespace My.name.space
    {
        class myClass
        {       
            public CustomObject Name
            {
                get { return new CustomObject (this.Dog); }
                set { return; }
            }

        }
    }

set { return; }的目的是什么?

我不明白 set return 的用途。

我认为您可以完全删除 set 访问器。

【问题讨论】:

  • 无操作 set 允许尝试将属性设置为编译,然后静默失败。如果你对你的雇主怀恨在心,而你刚刚被解雇,也许这是有道理的。如果财产是虚拟的,可能会有一些意义,但我仍然不喜欢它。 return 仅用于打字练习。
  • return;可以省略。无论如何,设置方法都是无效的。
  • 作为一个密切相关的,我认为这段代码应该是一个方法而不是一个属性,根据这些MSDN Guidelines:“Do use a method (if) ... 操作返回不同的结果每次调用它,即使参数没有改变”。我觉得“空”设置器是程序员说,“嘿,'设置'任何东西都没有意义,因为'get'每次都会返回一个新对象”,但这只是代码味道首先它不应该是一个属性。
  • @Quantic 有一个很好的观点——尽管也可能是该类应该保留一个私有的CustomObject 字段,当Dog 的值发生变化时该字段会更新;在这种情况下,Name 将是一个返回该字段的属性。当然,如果您在旧代码库的一个尘土飞扬的角落发现它并且它没有主动导致任何问题,那么它可能不是一轮回归错误轮盘的高优先级。
  • 如果您对某个问题投了反对票,请留下理由。

标签: c# accessor


【解决方案1】:

没有。有些人不太清楚只读属性可以通过不包含set 来更简单地表达

public Derp MuhDerp { get { return _derp; } }

CSharpie 在评论中提出的有趣点...

如果您必须拥有set,因为它是在接口中定义的,您可以添加set,但省略返回:

public Derp MuhDerp { get { return _derp; } set { } }

当然,如果接口定义了一个 setter,你可能应该确保它按预期工作:)

【讨论】:

  • 除非它由接口定义。
【解决方案2】:

基本上是给人一种假象,有一个二传手,嗯,有,但什么也没做。但这样做可能是为了让某些接口或父类保持快乐:

public CustomObject Name
{
   get { return new CustomObject( this.Dog ); }
   set { return; } // does absolutely nothing
}

这是一个类:

public abstract class A {
   public abstract void DoWork();
   public abstract string SomeProperty { get; set; }
}

这里给人一种它正在实现抽象接口的错觉,但它实际上并没有实现所有东西:

public class B : A {
   public override string SomeProperty
   {
      get
      {
         return "whatever";
      }

      set
      {
         return; // keep interface happy
      }
   }

   public override void DoWork() {
      // I am not doing nothing but compiler is happy
   }
}

该代码也破坏了Liskov Substitution Principle

【讨论】:

    【解决方案3】:

    这只是意味着“不要做任何事情,我不想做作业”。这就像二传手中的无操作一样。它也相当于一个空的 setter,即set { }。这是一个偏好问题,真的;我猜有些人不喜欢有空的代码体。

    当然,您通常不会那样做(正如 Will 指出的那样)。您将只使用只读属性,但有一个关键区别:使用只读属性时,尝试设置它会在编译时失败;如果您使用的是您询问的那个,那么它根本不会失败,它只会在运行时“什么都不做”。

    您使用哪一种很大程度上取决于您希望应用程序做什么。我会指出,使用这种方法(而不是只读属性)可能会导致代码脆弱,因为程序员可能没有意识到他们故意分配值的尝试被忽略了。

    【讨论】:

      【解决方案4】:

      C# 中的属性只是特殊方法的语法糖果。

      “常规”属性,如

      public int Foo {get;set;}
      

      实际上是(类似的东西)

      int _foo;
      public int get_Foo() { return _foo;}
      public void set_Foo(int value) { _foo = value;}
      

      但是你可以指定你自己,在 setter 和 getter 中发生了什么

      public int Foo { get { return 47; } set { Console.WriteLine(value); } }
      

      因此,以您的示例为例,编译器会将其转换为

      public CustomObject get_Name() { return new CustomObject (this.Dog); }
      public void set_Name(CustomObject value) { return; }
      

      在 set-Method 中什么都不做。那么为什么有人会这样做呢? 有几个原因是有道理的:

      • 他们希望稍后向该 setter 引入功能,因此现在将其用作占位符
      • setter 是必需的,因为 Property 来自接口,但在具体实现中设置值是没有意义的
      • 一些基于反射的 API 或东西需要一个 set-method,即使它没有被使用。

      【讨论】:

        【解决方案5】:

        这和只读属性一样,但是可以设置属性(显然没有意义)。

        【讨论】:

          【解决方案6】:

          这里有一些很好的答案(我知道这是一个老问题),但我想提供一些额外的背景信息,说明这是什么,什么时候可能有用,以及我如何在生产代码中使用它。

          首先,答案是:这通常没有用。只需定义一个只读属性。正如其他人所说,您完全正确,您可以删除该集合并具有几乎相同的效果 - 除了无法再分配该属性。

          现在,这是有用的地方。对于我编写的许多较小的微服务,我使用 Azure Tables 进行存储。这是一个键值数据库,其中您的键分为两部分:PartitionKey 和 RowKey。它们是不言自明的。

          通常我会得到几个小表(例如保存基本应用程序管理设置的表),这些表对于使用 PartitionKey 没有意义 - 即它们只有一个识别信息,例如作为一个 id 和一个值。

          Azure.Data.Tables 库非常好,它提供了一个接口来为您的 DTO 实现。实现此接口通常如下所示:

          using Azure;
          using Azure.Data.Tables;
          
          namespace SmartsheetIntegration.Qar.DataStores.Models;
          
          public class MyDto : ITableEntity 
          {
              public MyDto() {}
          
              public MyDto(string partitionKey, string rowKey)
              {
                  PartitionKey = partitionKey;
                  RowKey = rowKey;
              }
          
              public string PartitionKey { get; set; }
              public string RowKey { get; set; }
              public DateTimeOffset? Timestamp { get; set; }
              public ETag ETag { get; set; }
          }
          

          现在,这些简单的应用设置怎么样?我想确保它们永远以 PartitionKey 结尾,因为我需要确定如果我想检索所有这些,我可以查询 'PartitionKey = ""' 并取回所有内容。

          解决这个问题的简单方法是:

          using Azure;
          using Azure.Data.Tables;
          
          namespace SmartsheetIntegration.Qar.DataStores.Models;
          
          public class MyDto : ITableEntity 
          {
              public MyDto() {}
          
              public MyDto(string partitionKey, string rowKey)
              {
                  PartitionKey = partitionKey;
                  RowKey = rowKey;
              }
          
              public string PartitionKey
              {
                  get => "";
                  set { } // the same as set { return; }
              }
              public string RowKey { get; set; }
              public DateTimeOffset? Timestamp { get; set; }
              public ETag ETag { get; set; }
          }
          

          现在 Azure Tables 可以在其库中为所欲为,但我可以保证保存到数据库中的 PartitionKey 将始终为空字符串。

          所以是的,这有用的情况并不多——但有一些接口实现是有意义的。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-11-18
            • 2013-03-20
            • 1970-01-01
            • 2018-10-24
            相关资源
            最近更新 更多