Какие-либо ORMs.NET используют конструкторов “правильно”?

Вы смотрите на неоптимизированный код, поэтому изучение его на предмет производительности не очень важно. Если вы посмотрите на оптимизированный код для своих примеров, вы обнаружите, что он вообще не выполняет сравнения! Оптимизатор замечает, что переменная переключения sc всегда имеет значение 1, поэтому он удаляет недостижимый case 2.

Оптимизатор также видит, что переменная a не используется после назначения, поэтому он также удаляет код из case 1, оставляя main() пустую функцию. И он удаляет функцию пролог / эпилог, которая манипулирует rbp, так как этот регистр не используется.

Таким образом, оптимизированный код заканчивается одинаково для любой версии вашей функции main():

main:
    xor eax, eax
    ret

Короче говоря, для кода в вопросе не имеет значения, в каком порядке вы ставите case, потому что ни один из этого кода не будет сгенерирован вообще.

Будет ли порядок case иметь значение в более реальном примере, где код фактически генерируется и используется? Возможно нет. Обратите внимание, что даже в неоптимизированном сгенерированном коде обе версии проверяют два значения case в числовом порядке, проверяя сначала для 1, а затем для 2, независимо от порядка в исходном коде. , Очевидно, что компилятор выполняет некоторую сортировку даже в неоптимизированном коде.

Обязательно обратите внимание на комментарии Гленна и Лундина: порядок разделов case - не единственное изменение между вашими двумя примерами, реальный код также отличается. В одном из них значения case соответствуют значениям, установленным в a, но не так в другом.

Компиляторы используют различные стратегии для операторов switch / case в зависимости от используемых фактических значений. Они могут использовать ряд сравнений, как в этих примерах, или, возможно, таблицу переходов. Может быть интересно изучить сгенерированный код, но, как всегда, если производительность имеет значение, следите за настройками оптимизации и тестируйте в реальной ситуации.

7
задан Community 23 May 2017 в 12:19
поделиться

8 ответов

Ей-богу, я думаю, я понял!

Спасибо всем за их вклад, но я собираюсь ответить на свой вопрос. Я просто потратил час или около того, копаясь в каталоге PoEAA , размышляя о принципах объектно-ориентированного проектирования и смешивая их с глубокими размышлениями о языке C # и платформе .NET.

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

По сути, без реализации ленивой загрузки внутри классов предметной области (серьезное препятствие для игнорирования настойчивости и гибкости), нет способа сделать это без создания подклассов классов предметной области. Это подклассификация является причиной того, что NHibernate требует виртуальных свойств.

1
ответ дан 7 December 2019 в 05:30
поделиться

Я думаю, что большинство ORM действительно поддерживают эту концепцию, по крайней мере, DataObject.Net поддерживает. Этот код работает так, как ожидалось:

[HierarchyRoot(typeof(KeyGenerator), "Id")]
public class Message : Entity
{
  [Field]
  public int Id { get; private set; }

  [Field(Length = 100)]
  public string Text { get; private set; }

  public Message(string Text)
  {
    Text = text;
  }
}

EDIT: DataObjects хранят данные во внутреннем транзакционном состоянии и используют специальный конструктор материализации, созданный PostSharp. Конечно, это не так тривиально, если ORM использует объекты poco.

3
ответ дан 7 December 2019 в 05:30
поделиться

К сожалению, в .NET это невозможно без какой-либо разметки конструкторов.

Сигнатура метода, хранящаяся для каждого конструктора в метаданных сборки, содержит только тип каждого параметра для конструктор. ЛЮБОЙ .NET ORM не может точно знать, какой конструктор использовать. Все, что видит ORM, выглядит примерно так:

.ctor()
.ctor(string, string)
.ctor(string, string, string)

ORM не может узнать, какой параметр .ctor соответствует, например, FirstName, LastName и MiddleName для вашего объекта Customer.

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

public Customer ([Property ("FirstName")] string FirstName, [Property ("LastName")] string LastName, [Property ("

2
ответ дан 7 December 2019 в 05:30
поделиться

Как вы думаете, почему это неправильно? Вы хотите, чтобы ваш OR / M выполнял бизнес-логику при воссоздании объекта? ИМХО, нет.

Когда вы загружаете объект из БД, OR / M должен иметь возможность воссоздать объект, несмотря ни на что. Установка некоторого значения во время пересчета не должна приводить к запуску какой-то логики, которая изменяет другое значение (которому, возможно, также следует присвоить значение ORM ...)

Тем не менее, я думаю, что конструктор должен содержать только параметры для тех полей, которые являются обязательными во время создания объекта, чтобы объект находился в «допустимом» состоянии. Кроме того, у вас могут быть общедоступные свойства, доступные только для чтения, которым было присвоено значение в результате некоторых вычислений, и которые также должны быть сохранены.
Если вы чувствуете, что отражение - это «запах» для воссоздания объектов, как вы собираетесь справиться с этой ситуацией? Вам нужно будет каким-то образом создать общедоступный метод, который сможет установить это значение «только для чтения», но это нарушает инкапсуляцию, и вы этого тоже не хотите.

1
ответ дан 7 December 2019 в 05:30
поделиться

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

Что необходимо учитывать и чего, похоже, не хватает на данный момент всем основным ORM, так это воссоздания объект домена из его последнего известного состояния, хранящегося в базе данных или любом другом хранилище данных, НЕ является по своей сути операцией построения или изменения; поэтому не следует использовать ни конструкторы, ни установщики свойств. Скорее, механизм фреймворка, который наиболее точно соответствует этому виду операции, - это сериализация! Уже существуют распознанные шаблоны для сохранения состояния объекта и последующего его восстановления через интерфейс ISerializable, стандартный конструктор сериализации и т. д. Сохранение объекта в базе данных принципиально не отличается от сохранения его в потоке; фактически, одно из значений перечисления StreamingContextStates, которое используется во время сериализации, - это Persistence !. IMHO, это должен быть стандартный подход при разработке любого механизма сохранения. К сожалению, я не знаю ни одного ORM, который поддерживает это из коробки.

Также следует отметить, что объект, который был разработан для сериализации, по-прежнему является POCO; настойчивое незнание НЕ нарушалось. Ключевым моментом здесь является то, что объект домена должен лучше знать, какие данные необходимы для их сохранения и восстановления, а также в каком порядке эти данные должны быть восстановлены (что часто имеет значение). Что объекту НЕ нужно знать, так это конкретный механизм, с помощью которого он будет храниться:

1
ответ дан 7 December 2019 в 05:30
поделиться

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

Таким образом, может быть такой преобразователь ИЛИ, но он определенно будет иметь ограничения. Как показано в данном примере, я бы не стал рассматривать обход инкапсуляции объекта с помощью OR mapper как плохой дизайн, а как требование в некоторых ситуациях.

0
ответ дан 7 December 2019 в 05:30
поделиться

г. Скит недавно предложил модель «строителя». Я сделал его публичным классом в классе POCO. Он имеет те же свойства, что и POCO, но все для чтения / записи. POCO доступен только для чтения там, где это необходимо, но только для ЧАСТНОГО НАБОР. Таким образом, конструктор может установить свойства при создании экземпляра POCO и не иметь фанковых аргументов для конструктора. Это своего рода "неизменяемость попсиклов".

0
ответ дан 7 December 2019 в 05:30
поделиться

Это зависит от того, какие значения вы считаете значениями, которые не следует изменять. Автоинкременты, вычисляемые столбцы и т. Д. Являются хорошими кандидатами для этого.

Это, безусловно, возможно , я использую ORM, который я написал, и он выдает исключение, если вы пытаетесь установить значение свойство только для чтения.

Обновление:

Помните, что конструкторы также используются для постоянных данных. Обычно ваш объект принимает PK в конструкторе, и он автоматически получает эту запись.

0
ответ дан 7 December 2019 в 05:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: