Подтвердить что ты не робот

Классы DTO против структуры

Итак, на самом деле этот вопрос является моим текущим краеугольным камнем. Я работаю над рефакторингом своего личного проекта, стараюсь повысить производительность, оптимизировать использование памяти, сделать код простым и понятным. У меня разные уровни приложений (на самом деле, DAL, BLL, ServiceAgents, которые являются службами WCF). Я использую Entities/Models/DTO для передачи данных между этими слоями, которые являются безстоящими (вообще не имеют никакой логики). В настоящее время это такие объекты, как

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

Раньше я использовал такой подход, это как "лучшая практика", не так ли? Это лучший способ хранения переданных данных? Что делать, если я изменяю его для struct следующим образом:

public struct Peson
{
    public ComplexIdentifier ComplexId;
    public string Name;
}
public struct ComplexIdentifier
{
    public int LocalId;
    public int GlobalId;
}

Является ли это лучшим способом с точки зрения использования производительности/памяти? Или, может быть, есть какие-то ловушки, действующие таким образом?

4b9b3361

Ответ 1

Для стандартных объектов DTO вы захотите придерживаться класса.

A struct имеет гораздо более ограниченный диапазон потенциальных вариантов использования, чем классы. Существуют также проблемы с эффективностью, когда типы struct становятся слишком большими (не забывайте, что они являются типами значений и копируются при передаче), как указано в Руководства MSDN о типах значений. Не говоря уже о большом количестве gotchas, когда вы начинаете с типов struct, открытых через свойства, или случайно помещаете его при ссылках на интерфейсы или изменяете их...

Я не говорю, что не использую struct, когда это уместно, но мне очень редко приходится использовать типы struct на нашем основном рабочем столе приложение, которое является многоуровневым и имеет типы DTO.


На проблему с производительностью нельзя ответить просто как struct vs. class. Вам нужно будет использовать средства профилирования, такие как dotTrace или МУРАВЬЕВ, чтобы найти горячие точки и перейти оттуда. Проблемы с производительностью не являются тривиальными, и, как правило, наилучшим инструментом является начало ответа.

Ответ 2

Два наилучших варианта для объекта передачи данных обычно должны быть либо глубоко неизменяемым объектом класса, либо структурой с открытыми полями типов, подходящими для использования в качестве объектов передачи данных. Иногда могут использоваться и другие типы структур, но структуры с открытым полем являются, пожалуй, самыми простыми, и эта простота является великой добродетелью.

Понятие о том, что изменчивые структуры являются злыми, восходит к некоторым ранним компиляторам С#, в которых

  SomeReadonlyStruct.SomeProperty = 5;

будет молча преобразован компилятором в:

  var temp = SomeReadonlyStruct;
  temp.SomeProperty = 5;

Скрытие структурных полей за свойствами readonly было попыткой обеспечить, чтобы прежний оператор отказывался компилировать вместо того, чтобы уступать сломанный код. Поскольку новые компиляторы откажутся мутировать записываемые поля readonly structs, больше нет необходимости обертывать поля в свойствах только для чтения.

Структуры с открытыми полями имеют огромное преимущество по сравнению с другими типами объектов передачи данных: каждая структура, которая открыла поля типов, подходящих для передачи данных, и других членов, кроме конструктора, ведет себя одинаково, без сюрпризов, Тот, кто никогда не использовал структуры, может быть немного удивлен тем фактом, что они не действуют как классы, но тот, кто понимает, как работает любая такая структура, поймет, как все они работают.

Рассмотрим следующий код:

  customerPhone = someDataSource.GetPhoneNumber(customerID);
  customerPhone.Extention = "5309"

Некоторым людям не нравится тот факт, что если customerPhone является структурой открытого поля, установка свойства Extension не влияет на информацию в someDataSource. Хотя верно, что запись поля структуры не будет обновлять что-либо еще, это намного лучше, чем было бы, если customerPhone был измененным типом класса. Любой, кто понимает, что customerPhone - тип структуры с открытым полем, будет знать, что изменения его членов не будут влиять ни на что другое. В отличие от этого, если customerPhone является изменяемым типом класса, код, подобный приведенному выше, может обновить someDataSource, изменив номер телефона, связанный с этим customerID. Или это не так. Или, если один номер телефона был связан с двумя значениями customerID, приведенный выше код может изменить их оба. Количество кода, которое, возможно, придется изучать, чтобы точно определить, какие эффекты и побочные эффекты может иметь вышеуказанный код, будет довольно большим. Хуже того, может быть трудно быть уверенным, что никто ничего не пропустил.

Есть определенные места, где прохождение вокруг ссылок на объекты класса может быть более эффективным, чем передача вокруг структур. Также есть несколько случаев, когда объекты mutable класса могут быть полезными держателями данных в классе. Однако некоторые общие обертки могут облегчить перенос структуры в изменяемый или неизменяемый класс, и обмен информацией между этими типами классов.

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; }
}

Такая конструкция будет намного более неудобной без изменяемых структур.

Ответ 3

Является ли это лучшим способом с точки зрения использования производительности/памяти?

Нет. Структуры представляют собой типы значений, поэтому они копируются по значению. Это означает, что вместо копирования только ссылки вы всегда будете копировать полный объект. Во всяком случае, он, вероятно, будет немного медленнее и будет использовать больше памяти (поскольку объект будет дублироваться).

Еще одна причина, почему вы не должны этого делать: всегда следует избегать изменчивых структур, поскольку они могут вызвать неожиданное поведение, если вы не будете осторожны.

Ответ 4

A struct может быть более опасным, так как типы значений обрабатываются гораздо более по-разному CLR и если они плохо написаны (например, измененная структура), могут создавать ужасные головные боли. Кроме того, если ваш тип содержит много полей, а затем передается от метода к методу, вы будете копировать каждое значение поля для каждого вызова метода, тем самым используя больше памяти, чем если бы вы использовали класс в первую очередь.

Использование DTO (объекты передачи данных), которые будут способствовать разделению состояния и поведения. Это может быть хорошим дизайном, если все сделано правильно (и в большинстве случаев вы реализуете этот шаблон с использованием классов, а не структур).

Кроме того, конкретный случай использования struct как DTO object кажется ошибочным, поскольку он вводит ненужный redundancy. Поскольку structs cannot inherit other structs, вы не можете выразить is-a отношения. Что вы делаете, когда у вас есть Customer, который наследует от Person. Вы повторяете всю структуру Person properties in the Customer? Вы встраиваете структуру Person внутри структуры Customer? Ни один подход не идеален. Если вы, по крайней мере, использовали классы, , вы могли бы расширить клиент Person.

Ответ 5

Вы должны использовать подход класса, структурный подход может быть даже медленнее, поскольку структуры являются типами значений, и копии будут сделаны, если вы передадите их в качестве параметров функции. Поэтому для ваших DTO придерживайтесь класса aproach.

Ответ 6

Мое мнение: классы лучше.

С помощью классов вы можете реализовать интерфейс INotifyPropertyChanged, что будет очень полезно, если вы выполните привязку данных.

Вы также можете иметь некоторые частные поля, такие как "ID" только с "get" -property, вы можете добавить некоторые методы в свой класс, вы можете сделать ваши сущности сериализуемыми.
Все, что я хочу сказать, что вы более гибкие с классами, и я не думаю, что в этом случае существует большая разница в производительности между структурой и классами.

Вот очень хорошая книга, которая мне очень помогла, разработав nTier-приложения: http://msdn.microsoft.com/en-us/library/ee817644.aspx

Посмотрите там. В нем говорится: "Выбор между структурами и классами. Для простых бизнес-объектов, которые не содержат иерархические данные или коллекции, рассмотрим определение структуры для представления хозяйствующий субъект. Для сложных хозяйствующих субъектов или для субъектов бизнеса, которые требуют наследования, определите сущность как класс вместо этого. "