【问题标题】:C# syntax sugar - new way to set object attributes?C# 语法糖 - 设置对象属性的新方法?
【发布时间】:2011-04-25 23:24:36
【问题描述】:

对于这里的铁杆 C# 编码人员来说,这似乎是一个完全愚蠢的问题 - 然而,我刚刚在 AWS SDK 论坛中遇到了一个示例代码的 sn-p 并且完全被它扫视了:

   RunInstancesRequest runInstance = new RunInstancesRequest()
    .WithMinCount(1)
    .WithMaxCount(1)
    .WithImageId(GetXMLElement("ami"))
    .WithInstanceType("t1.micro");

这很容易让人想起旧的 VB6 With ... End With 语法,我一直在感叹 C# 中没有这种语法——我已经在我的 VS2008 项目中编译了它,它很有效,节省了许多单独引用这些属性的单独行.

我确定我过去读过文章,解释了为什么 VB6 风格的 With-block 不在 C# 中,所以我的问题是:这种语法 always 存在于语言,还是最近的 .NET 更改启用了它?我们可以在同一个糖中覆盖所有对象实例化,然后是属性更改吗?

【问题讨论】:

  • 当然,如果你愿意,你可以实现所有这些方法。但是为什么不直接使用对象初始化语法呢?
  • 这里的答案很好,但我只能接受一个 - 所以目前它是专门指 Fluent Interface 的答案,因为文章中的示例非常清楚这是怎么回事。我有点尴尬,因为我自己没有建立直观的链接,发现整个线条的形式是“A.B.C.D;”,但我以前从未见过这种技术。弓上的另一根弦! :)

标签: c# syntactic-sugar


【解决方案1】:

【讨论】:

    【解决方案2】:

    它一直存在于 C# 中,而且确实存在于任何 C 风格的 oo 语言中(嗯,除了 C 本身之外最流行的 C 风格的语言!)

    将它与 VB6 With...End With 语法进行比较是不公平的,因为在这种情况下发生的事情要清楚得多(关于 VB6 的 With...End With,我要说的唯一好处是至少它不像不如 Javascripts,因为它需要前面的点)。

    正如人们所说,结合了“流畅的界面”和 . 运算符允许在其前后有空格这一事实,因此我们可以将每个项目放在换行符上。

    StringBuilder 是 C# 中最常见的情况,如:

    new StringBuilder("This")
      .Append(' ')
      .Append("will")
      .Append(' ')
      .Append("work")
      .Append('.');
    

    一个相关但不完全相同的模式是链接一个不可变对象的方法,该对象返回与以下相同类型的不同对象:

    DateTime yearAndADay = DateTime.UtcNow.AddYears(1).AddDays(1);
    

    还有一个是从 LINQ 相关方法返回修改后的 IEnumerable<T>IQueryable<T> 对象。

    这些虽然返回不同的对象不同,而不是修改可变对象并返回相同的对象。

    它在 C++ 和 Java 中比在 C# 中更常见的主要原因之一是 C# 具有属性。这使得分配不同属性的最惯用方法是调用相关的 setter,这在语法上与设置字段相同。然而,它确实阻止了流畅界面习惯用法的大部分最常见用法。

    就个人而言,由于不能保证流畅的界面习语(没有什么可说的 MyClass.setProp(32) 应该返回 this 或者实际上,它不应该返回 32 这在某些情况下也很有用),并且因为它在 C# 中不是惯用的,我更愿意避免使用 StringBuilder,这是一个众所周知的例子,它几乎在 C# 中作为单独的 StringBuilder 成语存在

    【讨论】:

      【解决方案3】:
      RunInstancesRequest runInstance = new RunInstancesRequest()
      .WithMinCount(1)
      .WithMaxCount(1)
      .WithImageId(GetXMLElement("ami"))
      .WithInstanceType("t1.micro");
      

      ==

      RunInstancesRequest runInstance = new RunInstancesRequest().WithMinCount(1).WithMaxCount(1).WithImageId(GetXMLElement("ami")).WithInstanceType("t1.micro");
      

      我不知道这是否被认为是语法糖,或者只是纯粹的格式。

      【讨论】:

      • +1:. 周围的空格被(并且一直被)编译器完全忽略。
      【解决方案4】:

      我希望有一个将所有这些属性值作为参数并在类中设置它们的构造函数。

      【讨论】:

      • +1。我不喜欢任何让部分构建的类存在的东西。我只是忍受 LINQ2SQL 或其他 ORM 作为 OO-ORM 阻抗的产物,但大多数时候没有理由。并不意味着它不能与适当的构造函数和类不变量一起使用,但我可以看到这将如何鼓励摆脱它。
      【解决方案5】:

      我认为这种技术与 VB 中的 With... 语法不同。我认为这是链接的一个例子。每个方法都返回一个自身的实例,因此您可以链接方法调用。

      Method-Chaining in C#

      【讨论】:

        【解决方案6】:

        此语法适用于RunInstancesRequest 的原因是您进行的每个方法调用都返回原始实例。出于同样的原因,同样的概念也可以应用于 StringBuilder,但并非所有类都有以这种方式实现的方法。

        【讨论】:

          【解决方案7】:

          这样不是更好吗?

          RunInstancesRequest runInstance = new RunInstancesRequest 
          {
              MinCount = 1, 
              MaxCount = 1, 
              ImageId = GetXMLEleemnt("ami"), 
              InstanceType = "t1.micro"
          };
          

          【讨论】:

          • 我同意,对于设置属性/构造函数,这是一种更好的语法。但是在您使用现有项目的情况下,并且通常会修改多个属性或调用链中的多个方法,流利的接口会大放异彩。这是 jQuery 非常好用的众多原因之一。
          • 你不能在不可变对象上使用它。我个人认为只有在原始对象没有被修改的情况下才应该使用这种语法(比如在 Linq 中)。
          • 每一步增加一个对象。而且我很确定 Linq 会创建一个实例,该实例在查询创建的每一步都实现 IEnumerable。每个查询评估步骤一个 IEnumerator。我认为虚假对象并不重要,因为它们可能会在第 0 代 GC 中被收集。
          【解决方案8】:

          他们实现了所有这些方法,每个方法也将返回RunInstancesRequest 对象(又名this)。它被称为Fluent Interface

          【讨论】:

          【解决方案9】:

          这种语法一直存在

          【讨论】:

            【解决方案10】:

            它不是语法糖。这些方法只是设置一个属性并返回this 对象。

            【讨论】:

              猜你喜欢
              • 2016-03-22
              • 2011-07-16
              • 1970-01-01
              • 1970-01-01
              • 2015-03-14
              • 2012-05-22
              • 2019-03-08
              • 1970-01-01
              • 2013-12-23
              相关资源
              最近更新 更多