C# DTO类与结构

C# DTO类与结构,c#,struct,dto,n-tier-architecture,C#,Struct,Dto,N Tier Architecture,所以,这个问题实际上是我目前的重点。 我正在对我的个人项目进行重构,试图提高性能,优化内存使用,使代码简单明了。我有不同的应用层(实际上,DAL、BLL、ServiceAgents,即WCF服务)。我使用实体/模型/DTO在这些层之间传递数据,这是无状态的(根本没有任何逻辑)。目前它们是这样的对象: public class Person { public ComplexId Id { get; set; } public string Name { get; set; } // .

所以,这个问题实际上是我目前的重点。 我正在对我的个人项目进行重构,试图提高性能,优化内存使用,使代码简单明了。我有不同的应用层(实际上,DAL、BLL、ServiceAgents,即WCF服务)。我使用实体/模型/DTO在这些层之间传递数据,这是无状态的(根本没有任何逻辑)。目前它们是这样的对象:

public class Person
{
  public ComplexId Id { get; set; }
  public string Name { get; set; }
  // ...
}
public struct Person
{
    public ComplexIdentifier ComplexId;
    public string Name;
}

public struct ComplexIdentifier
{
    public int LocalId;
    public int GlobalId;
}
我曾经用过这样的方法,这就像一个“最佳实践”,是吗?这是存储传输数据的最佳方式吗?如果我将其更改为struct,如下所示:

public class Person
{
  public ComplexId Id { get; set; }
  public string Name { get; set; }
  // ...
}
public struct Person
{
    public ComplexIdentifier ComplexId;
    public string Name;
}

public struct ComplexIdentifier
{
    public int LocalId;
    public int GlobalId;
}

从性能/内存使用的角度来看,这是更好的方法吗?或者可能存在某种这样的陷阱?

对于标准DTO实体,您将希望坚持使用该类

与类相比,
struct
的潜在用例范围要小得多。当
struct
类型变得太大时(别忘了,它们是值类型,传递时会被复制),也存在效率问题,如中所述。更不用说,当您开始通过属性公开
struct
类型时,或者在引用接口时意外地将其装箱,或者使其可变时,会出现大量的问题

我不是相关的
struct
,但我很少发现自己需要在我们的主桌面应用程序中使用
struct
类型,它是分层的,具有DTO类型。
性能问题的答案不能像
struct
class
那样简单。您需要使用分析工具,如或,以便找到热点并从那里开始。性能问题并非无关紧要,好的工具通常是答案的开始

从性能/内存使用的角度来看,这是更好的方法吗

不。结构是值类型,所以它们是按值复制的。这意味着,您将始终复制完整对象,而不是仅复制引用。如果有的话,它可能会稍微慢一点,并使用更多的内存(因为对象将被复制)


您不应该这样做的另一个原因是:应始终避免可变结构,因为如果您不小心,它们可能会导致意外行为。

A
struct
可能更危险的是,
CLR
处理值类型的方式更为不同,如果编写得不好(例如可变结构)会引起严重的头痛。此外,如果您的类型包含许多字段,然后从一个方法传递到另一个方法,那么您将在每个方法调用上复制每个字段的值,从而使用比最初使用类更多的内存

使用(数据传输对象),这将鼓励分离状态和行为。如果操作得当,这可能是一个很好的设计(在大多数情况下,您将使用类而不是结构来实现此模式)


此外,使用
struct
作为
DTO对象
的具体情况似乎有缺陷,因为它引入了不必要的
冗余
。由于结构不能继承其他结构,因此不能表示is-a关系。当您拥有继承自
Person
Customer
时,您会怎么做。是否重复Customer结构中的所有
人员属性?您是否将Person结构嵌套在Customer结构中?这两种方法都不理想。如果您至少使用了类,您可以让Customer extend Person

您应该使用类方法,结构方法甚至可能更慢,因为结构是值类型,并且无论您将其作为函数参数传递到哪里,都会生成副本。因此,对于您的DTO,请坚持使用类aproach

我的意见是:上课更好

通过类,您可以实现INotifyPropertyChanged接口,如果您进行数据绑定,这将非常有用

您还可以有一些私有字段,如“ID”,仅带有“get”-属性, 您可以向类中添加一些方法,使实体可序列化。
我想说的是,类更灵活,我不认为在这种情况下,struct和类之间有任何巨大的性能差异

这是一本非常好的书,它通过设计nTier应用程序帮助了我很多:

看看那里。它说: “在结构和类之间进行选择。对于没有 包含分层数据或集合,考虑定义一个结构来表示 业务实体。对于复杂的业务实体,或对于
如果需要继承,请将实体定义为类。“

数据传输对象的两个最佳选择通常应该是深度不可变的类对象,或者是具有适合用作数据传输对象的类型的公开字段的结构。其他类型的结构有时也可以使用,但公开字段结构是迄今为止最简单的,这种简单性是一个很大的优点

易变结构是邪恶的概念可以追溯到一些早期的C#编译器

SomeReadonlyStruct.SomeProperty = 5;
如果没有可变的结构,这样的构造会更加笨拙。

+1。一句忠告:@Steven当然,我在我的回答中添加了这个链接——有点潜意识;-)同意。为了缓解在向这些对象复制值和从这些对象复制值时遇到的一些麻烦,请利用[AutoMapper](AutoMapper.org)。用作数据传输对象的可变类比可变结构更糟糕。“类”(这是一个简单的类;p)感谢大家的参与!我正在使用无状态类-我知道INotifyPropertyChanged,但根据我的任务,我不需要它。我也不需要向这个对象添加任何逻辑(方法)。和get only properties-struct可以有只读字段,对吗?从那以后,引入了只读结构,并扩展了按引用传递以返回值和带有“in”键的只读引用参数 interface IReadableHolder<T> { T Value {get;} } class MutableHolder<T> : IReadableHolder<T> { public T Value; IReadableHolder.Value {get {return Value;} } public MutableHolder(T newValue) { Value = newValue; } public MutableHolder(IReadableHolder<T> it) { Value = it.Value; } } class ImmutableHolder<T> : IReadableHolder<T> { T _Value; public Value {get {return _Value;} } public ImmutableHolder(T newValue) { _Value = newValue; } }