У меня есть большой объект:
class BigObject{
public int Id {get;set;}
public string FieldA {get;set;}
// ...
public string FieldZ {get;set;}
}
и специализированный, DTO-подобный объект:
class SmallObject{
public int Id {get;set;}
public EnumType Type {get;set;}
public string FieldC {get;set;}
public string FieldN {get;set;}
}
Лично я нахожу концепцию явного приведения BigObject в SmallObject - зная, что это односторонняя операция с потерей данных - очень интуитивно понятный и читаемый:
var small = (SmallObject) bigOne;
passSmallObjectToSomeone(small);
Это реализовано с использованием явного оператора:
public static explicit operator SmallObject(BigObject big){
return new SmallObject{
Id = big.Id,
FieldC = big.FieldC,
FieldN = big.FieldN,
EnumType = MyEnum.BigObjectSpecific
};
}
Теперь я мог бы создать SmallObjectFactory
класс с FromBigObject(BigObject big)
методом, который делал бы то же самое, добавлял его в инъекцию зависимостей и вызывал его при необходимости ... но мне он кажется еще более сложным и ненужным.
PS Я не уверен, если это актуально, но будет то, OtherBigObject
что тоже можно будет конвертировать в SmallObject
различные настройки EnumType
.
c#
object-oriented
.net
type-casting
Gerino
источник
источник
.ToSmallObject()
метод (илиGetSmallObject()
). Мгновенное отклонение разума - я знал, что что-то не так с моим мышлением, поэтому я спросил вас, ребята :)ToSmallObject
методе.Ответы:
Ни один из других ответов не является правильным по моему скромному мнению. В этом вопросе о потоке стека ответ с наибольшим количеством голосов утверждает, что код отображения должен храниться вне домена. Чтобы ответить на ваш вопрос, нет - вы используете операторы приведения не очень хорошо. Я бы посоветовал создать картографический сервис, который находится между вашим DTO и вашим доменным объектом, или вы можете использовать для этого автомаппер.
источник
Это ... не здорово. Я работал с кодом, который сделал этот хитрый трюк, и это привело к путанице. В конце концов, можно было бы ожидать , чтобы иметь возможность просто присвоить
BigObject
вSmallObject
переменную , если объекты связаны достаточно , чтобы бросить их. Однако это не работает - вы получаете ошибки компилятора, если пытаетесь, поскольку система типов не связана с ними. Оператору литья также неприятно создавать новые объекты.Я бы порекомендовал
.ToSmallObject()
метод вместо. Это более понятно о том, что на самом деле происходит, и о том, как многословно.источник
mildly distasteful
это занижение. К сожалению, язык позволяет подобным вещам выглядеть как типичные. Никто не мог бы предположить, что это была реальная трансформация объекта, если бы они не написали это сами. В команде из одного человека, хорошо. Если вы сотрудничаете с кем-либо, в лучшем случае это пустая трата времени, потому что вам нужно остановиться и выяснить, действительно ли это актерский состав или одно из тех безумных преобразований..ToSmallObject()
. Вряд ли когда-нибудь вы должны переопределить операторов.Get
подразумевает возврат существующей вещи. Если вы не изменили операции над маленьким объектом, дваGet
вызова вернут неравные объекты, что приведет к путанице / ошибкам / wtfs.Хотя я понимаю, почему вам нужно иметь
SmallObject
, я бы по-другому подошел к проблеме. Мой подход к этому типу проблем заключается в использовании Фасада . Его единственная цель - заключать в капсулуBigObject
и делать доступными только определенные элементы. Таким образом, это новый интерфейс в том же экземпляре, а не копия. Конечно, вы также можете захотеть выполнить копию, но я бы порекомендовал вам сделать это с помощью метода, созданного для этой цели в сочетании с фасадом (напримерreturn new SmallObject(instance.Clone())
).Фасад имеет ряд других преимуществ, а именно: он гарантирует, что определенные разделы вашей программы могут использовать только те элементы, которые доступны через ваш фасад, эффективно гарантируя, что он не может использовать то, о чем он не должен знать. В дополнение к этому, он также обладает огромным преимуществом, заключающимся в том, что у вас больше гибкости в изменении
BigObject
будущего обслуживания, при этом вам не нужно слишком беспокоиться о том, как оно используется в вашей программе. До тех пор, пока вы можете эмулировать старое поведение в той или иной форме, вы можете выполнятьSmallObject
работу так же, как и раньше, без необходимости везде менять свою программуBigObject
.Обратите внимание, это означает, что
BigObject
это не зависит,SmallObject
а скорее наоборот (как и должно быть по моему скромному мнению).источник
SmallObject
наSmallObject
илиBigObject
. По умолчанию этот подход заставляетSmallObject
избегать зависимостей от частных / защищенных членовBigObject
. Мы можем пойти еще дальше и избежать зависимости от частных / защищенных членовSmallObject
, используяToSmallObject
метод расширения.BigObject
таким образом загромождать . Если вы хотите сделать что-то подобное, вы бы гарантировали созданиеToAnotherObject
метода расширения внутриBigObject
? Это не должно вызывать беспокойства,BigObject
поскольку, по-видимому, он уже достаточно большой, как есть. Это также позволяет вам отделитьсяBigObject
от создания его зависимостей, то есть вы можете использовать фабрики и тому подобное. Другой подход сильно парыBigObject
иSmallObject
. Это может быть хорошо в данном конкретном случае, но это не лучшая практика, по моему скромному мнению.BigObject
связано с этимSmallObject
, это просто статический метод где-то, который принимает аргументBigObject
и возвращаетSmallObject
. Методы расширения на самом деле просто синтаксический сахар для более приятного вызова статических методов. Метод расширения не является частью изBigObject
, это совершенно отдельный статический метод. На самом деле это довольно хорошее использование методов расширения и очень удобно, в частности, для DTO-преобразований.Существует очень строгое соглашение о том, что приведение к изменяемым ссылочным типам сохраняет идентичность. Поскольку система обычно не допускает определяемые пользователем операторы приведения в ситуациях, когда объект типа источника может быть назначен для ссылки на тип назначения, есть только несколько случаев, когда определенные пользователем операции приведения были бы разумными для изменяемой ссылки. типы.
В качестве требования я хотел бы предложить, чтобы, учитывая, что
x=(SomeType)foo;
за этим последует некоторое время спустяy=(SomeType)foo;
, когда оба приведения применяются к одному и тому же объекту, ониx.Equals(y)
всегда и всегда будут истинными, даже если рассматриваемый объект был изменен между двумя приведениями. Такая ситуация может применяться, если, например, у одного есть пара объектов разных типов, каждый из которых содержит неизменную ссылку на другой, и приведение любого объекта к другому типу вернет его парный экземпляр. Это также может применяться к типам, которые служат оболочками для изменяемых объектов, при условии, что идентификаторы обертываемых объектов являются неизменяемыми, и два упаковщика одного и того же типа будут сообщать о себе как о равных, если они будут упаковывать одну и ту же коллекцию.Ваш конкретный пример использует изменяемые классы, но не сохраняет никакой формы идентичности; как таковой, я бы предположил, что это не подходящее использование оператора приведения.
источник
Это может быть хорошо.
Проблема с вашим примером заключается в том, что вы используете такие имена из примера. Рассмотреть возможность:
Теперь, когда у вас есть хорошая идея, что означает long и int , то и неявное приведение
int
к,long
и явное приведениеlong
к toint
вполне понятны. Также понятно, как это3
делается3
и это просто еще один способ работы3
. Понятно, как это не получитсяint.MaxValue + 1
в проверенном контексте. Даже то, как он будет работатьint.MaxValue + 1
в неконтролируемом контексте, приведет к тому, чтоint.MinValue
это не самая сложная вещь.Аналогично, когда вы приводите неявно к базовому типу или явно к производному типу, это понятно любому, кто знает, как наследование работает, что происходит, и каков будет результат (или как он может потерпеть неудачу).
Теперь, с BigObject и SmallObject, я не понимаю, как работают эти отношения. Если ваши настоящие типы таковы, что отношения приведения очевидны, тогда приведение может быть хорошей идеей, хотя в большинстве случаев, возможно, в подавляющем большинстве случаев, если это так, то это должно быть отражено в иерархии классов и нормального приведения на основе наследования будет достаточно.
источник
BigObject
может описатьEmployee {Name, Vacation Days, Bank details, Access to different building floors etc.}
, иSmallObject
может бытьMoneyTransferRecepient {Name, Bank details}
. Существует простой перевод изEmployee
вMoneyTransferRecepient
, и нет никаких оснований для отправки в банковское приложение больше данных, чем необходимо.