【问题标题】:DTOs. Properties or fields?DTO。属性或字段?
【发布时间】:2012-06-05 13:48:29
【问题描述】:

我需要创建一些 DTO 类来跨 WCF 传输我们的业务对象。

由于这些只是没有功能的数据包,我有什么理由不能只使用字段,还是有充分的理由将它们正确地公开为属性?

//fields
[DataContract]
class CustomerDTO
{
    [DataMember] public int     Id;
    [DataMember] public string  Name;
}

//or properties?
[DataContract]
class CustomerDTO
{
    [DataMember] public int    Id               { get; set; }
    [DataMember] public string Name             { get; set; }
}

【问题讨论】:

  • 我之前曾多次想过这个问题。你最终做了什么决定?
  • @JonathanPeel 这是很久以前的事了,但我想我只是选择了属性。相反,最近的答案为字段提供了很好的论据。

标签: c# wcf soa dto


【解决方案1】:

我永远不会直接公开字段,大多数公司在他们的标准中都禁止这样做。实际上,您完全抛弃了封装。 DTO,作为更复杂事物的贫乏表示,是一个奇怪的情况,因为它们的属性几乎打破了封装。就个人而言,我会使用这些属性,因为这就是它们的用途。如果您需要,它还可以让您实现“脏”功能等,如果您直接调整字段,这并不容易。

【讨论】:

  • 属性的一个问题是,如果属性具有结构类型,则访问该结构的任何部分都需要制作整个事物的额外临时副本。暴露结构字段时,不需要这种浪费的复制操作。
【解决方案2】:

既然这些只是没有功能的数据包,我有什么理由不能只使用字段

这里没有反对公共领域的有力论据。但请务必意识到,这只是因为 DTO 内部没有逻辑(行为),因此封装的正常参数不成立。

我仍然更喜欢属性,但在这里它们并不是必需的。

【讨论】:

  • 谢谢大家。将纯粹为了一致性而使用属性。
  • 隐藏逻辑到属性中是不是混淆了?
【解决方案3】:

DataMember 属性将与公共字段和属性一起使用,因此两者都可以。但是,我建议坚持使用属性。

特别是,如果您使用的是 StyleCop,那么您将破坏 rule SA1401

此规则存在的原因并不真正适用于您的情况,但如果您在持续集成服务器上运行 StyleCop 验证作为构建的一部分,这仍然是一个维护问题。

【讨论】:

  • 如果解决方案将这些 DTO 放置在特定位置,则可以在此特定规则上覆盖 stylecop,仅针对该位置。
  • 确实如此,但这仍然是一个需要解决的维护问题。
【解决方案4】:

你可以使用任何一个。由于它不会影响性能,因此如果您遇到一些不适用于公共字段的序列化框架或类似框架,则使用属性会更安全。

请注意,WCF 代理生成将使用 公共属性 及其支持的私有字段在客户端创建这些 DTO,即使您在服务端使用公共字段。如果您不希望这样,您需要在服务和客户端之间共享一个 DTO 库。

【讨论】:

    【解决方案5】:

    如果我能侥幸的话,我最喜欢带有只读字段的不可变 DTO:

    public class CustomerDTO
    {
        public CustomerDTO(int id, string name)
        {
            Id = id;
            Name = name;
        }
    
        public readonly int     Id;
        public readonly string  Name;
    
        // Override Equals and GetHashCode as well...
    }
    

    不可变记录有很多优点,例如结构相等,这使得自动化测试断言更容易编写。还有dispenses with the need to write and maintain separate Test Data Builders

    不过,这取决于序列化程序。 JSON.NET 可以处理不可变记录,但许多其他序列化程序不能。

    对于那些处理公共字段的人,我更喜欢字段而不是属性,仅仅是因为它更诚实; automatically implemented read/write properties provide no encapsulation.

    一些序列化程序坚持使用公共属性,并且不序列化字段。如果是这样的话,你就必须顺其自然。

    老实说,考虑到我为此付出了多少思考,这并不是让我夜不能寐的事情,因为最终,at the boundaries, applications aren't object-oriented。因此,OOD 的规则并不真正适用于 DTO。

    【讨论】:

    • 一如既往的出色回答。上周我突然想到为什么我们需要房产。他们没有增加任何价值。 DTO 是纯粹的数据传输 - 因此没有表现出任何行为。不可变 DTO 似乎要优越得多。我确信我在某处读到过关于不在构造函数中设置属性的信息。不知道这些信息是从哪里在线获得的。
    【解决方案6】:

    以下是我没有看到其他人提及的属性相对于字段的两个优势。

    1. 语法中的摩擦与功能正确匹配

    我认为默认行为应该是更安全的选择。对于字段,默认行为允许可变性,这是更危险的选择。必须添加关键字 readonly 以使字段不可变(在构造函数之外)。相反,自动属性的默认状态是不可变的;必须添加语法 set; 才能使属性可变(在构造函数之外)。

    1. Visual Studio's Code Lens 中给出的引用计数

    与字段不同,在 Visual Studio 中查看属性有一个“代码镜头”,其中包括其引用计数。由于这些附加信息,我能够比字段更快地理解和重构属性。当然,可以使用 Shift+F12 在 Visual Studio 中搜索对字段和属性等内容的引用,但这是一个需要时间的额外步骤。此外,在极少数情况下,一些项目包括多个目标。这使得 Shift+F12 搜索结果更难使用,因为对每个目标都执行了搜索。在合同中,属性的代码 Len 中给出的引用计数与项目目标的数量无关。

    结论

    不过,为了直接回答这个问题,我更喜欢使用可变属性(而不是显式构造函数),以确保我将使用序列化库中最快乐的路径(在 the answer of @ErenErsönmez 中提到)。

    【讨论】:

      猜你喜欢
      • 2011-06-19
      • 2013-05-20
      • 2020-10-06
      • 1970-01-01
      • 1970-01-01
      • 2017-02-21
      • 2012-03-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多