Tengo un gran objeto:
class BigObject{
public int Id {get;set;}
public string FieldA {get;set;}
// ...
public string FieldZ {get;set;}
}
y un objeto especializado tipo DTO:
class SmallObject{
public int Id {get;set;}
public EnumType Type {get;set;}
public string FieldC {get;set;}
public string FieldN {get;set;}
}
Personalmente, encuentro un concepto de convertir explícitamente BigObject en SmallObject, sabiendo que es una operación unidireccional que pierde datos, muy intuitivo y legible:
var small = (SmallObject) bigOne;
passSmallObjectToSomeone(small);
Se implementa utilizando el operador explícito:
public static explicit operator SmallObject(BigObject big){
return new SmallObject{
Id = big.Id,
FieldC = big.FieldC,
FieldN = big.FieldN,
EnumType = MyEnum.BigObjectSpecific
};
}
Ahora, podría crear una SmallObjectFactory
clase con FromBigObject(BigObject big)
método, que haría lo mismo, agregarlo a la inyección de dependencia y llamarlo cuando sea necesario ... pero para mí parece aún más complicado e innecesario.
PD: No estoy seguro de si esto es relevante, pero habrá OtherBigObject
que también se podrá convertir en una SmallObject
configuración diferente EnumType
.
c#
object-oriented
.net
type-casting
Gerino
fuente
fuente
.ToSmallObject()
método (oGetSmallObject()
). Un lapso momentáneo de la razón - Yo sabía que algo está mal con mi forma de pensar, por lo que te he pedido chicos :)ToSmallObject
método.Respuestas:
Ninguna de las otras respuestas tiene razón en mi humilde opinión. En esta pregunta de stackoverflow, la respuesta más votada argumenta que el código de mapeo debe mantenerse fuera del dominio. Para responder a su pregunta, no, su uso del operador de transmisión no es excelente. Aconsejaría hacer un servicio de mapeo que se encuentre entre su DTO y su objeto de dominio, o podría usar automapper para eso.
fuente
Es ... No genial. He trabajado con código que hizo este truco inteligente y me llevó a la confusión. Después de todo, esperaría poder asignarlo
BigObject
a unaSmallObject
variable si los objetos están lo suficientemente relacionados como para lanzarlos. Sin embargo, no funciona: obtienes errores del compilador si lo intentas, ya que, en lo que respecta al sistema de tipos, no están relacionados. También es un poco desagradable para el operador de fundición hacer nuevos objetos.Recomendaría un
.ToSmallObject()
método en su lugar. Es más claro lo que realmente está sucediendo y lo que es detallado.fuente
mildly distasteful
Es un eufemismo. Es desafortunado que el lenguaje permita que este tipo de cosas se vean como una tipografía. Nadie adivinaría que fue una transformación de objeto real a menos que la hayan escrito ellos mismos. En un equipo de una persona, bien. Si colaboras con alguien, en el mejor de los casos es una pérdida de tiempo porque tienes que detenerte y descubrir si realmente es un elenco, o si es una de esas transformaciones locas..ToSmallObject()
. Casi nunca debería anular a los operadores.Get
implica devolver una cosa existente. A menos que haya anulado las operaciones en el objeto pequeño, dosGet
llamadas devolverían objetos desiguales, causando confusión / errores / wtfs.Si bien puedo ver por qué necesitarías tener un
SmallObject
, abordaría el problema de manera diferente. Mi enfoque para este tipo de problema es usar una Fachada . Su único propósito es encapsularBigObject
y solo poner a disposición miembros específicos. De esta manera, es una nueva interfaz en la misma instancia, y no una copia. Por supuesto, es posible que también desee realizar una copia, pero le recomendaría que lo haga a través de un método creado para ese propósito en combinación con la Fachada (por ejemploreturn new SmallObject(instance.Clone())
).Facade tiene una serie de otras ventajas, como asegurar que ciertas secciones de su programa solo puedan hacer uso de los miembros disponibles a través de su fachada, garantizando efectivamente que no puede hacer uso de lo que no debería saber. Además de esto, también tiene la enorme ventaja de que tiene más flexibilidad para cambiar
BigObject
en el mantenimiento futuro sin tener que preocuparse demasiado por cómo se usa en todo su programa. Siempre que pueda emular el comportamiento anterior de una forma u otra, puede hacer que elSmallObject
trabajo sea el mismo que antes sin tener que cambiar su programa en todas partesBigObject
.Tenga en cuenta que esto significa
BigObject
que no dependeSmallObject
sino al revés (como debería ser en mi humilde opinión).fuente
SmallObject
mentiras esSmallObject
o noBigObject
. Por defecto, este enfoque obligaSmallObject
a evitar dependencias de miembros privados / protegidos deBigObject
. Podemos ir un paso más allá y evitar dependencias de miembros privados / protegidosSmallObject
mediante el uso de unToSmallObject
método de extensión.BigObject
esa manera. Si quisieras hacer algo similar, ¿justificarías la creación de unToAnotherObject
método de extensiónBigObject
? Estas no deberían ser las preocupaciones deBigObject
, ya que, presumiblemente, ya es lo suficientemente grande como es. También le permite separarseBigObject
de la creación de sus dependencias, lo que significa que podría usar fábricas y similares. El otro enfoque fuertemente parejasBigObject
ySmallObject
. Eso puede estar bien en este caso particular, pero no es la mejor práctica en mi humilde opinión.BigObject
siendo acopladoSmallObject
, es solo un método estático en algún lugar que toma un argumentoBigObject
y regresaSmallObject
. Los métodos de extensión realmente son simplemente azúcar sintáctica para llamar a los métodos estáticos de una manera más agradable. El método de extensión no es parte deBigObject
, es un método estático completamente separados. En realidad, es un uso bastante bueno de los métodos de extensión, y muy útil para las conversiones DTO en particular.Existe una convención muy fuerte que establece que los tipos de referencia mutables preservan la identidad. Debido a que el sistema generalmente no permite operadores de conversión definidos por el usuario en situaciones en las que un objeto del tipo de origen podría asignarse a una referencia del tipo de destino, solo hay unos pocos casos en los que las operaciones de conversión definidas por el usuario serían razonables para una referencia mutable tipos.
Sugeriría como un requisito que, dado
x=(SomeType)foo;
seguido en algún momento posteriory=(SomeType)foo;
, con ambos lanzamientos aplicados al mismo objeto,x.Equals(y)
debería ser siempre y para siempre verdadero, incluso si el objeto en cuestión fue modificado entre los dos lanzamientos. Tal situación podría aplicarse si, por ejemplo, uno tuviera un par de objetos de diferentes tipos, cada uno de los cuales tenía una referencia inmutable al otro, y lanzar cualquiera de los objetos al otro tipo devolvería su instancia emparejada. También podría aplicarse con tipos que sirven como envoltorios para objetos mutables, siempre que las identidades de los objetos que se envuelvan sean inmutables, y dos envoltorios del mismo tipo se reportarían como iguales si envolvieran la misma colección.Su ejemplo particular usa clases mutables, pero no conserva ninguna forma de identidad; como tal, sugeriría que no es un uso apropiado de un operador de casting.
fuente
Puede estar bien
Un problema con su ejemplo es que usa dichos nombres de ejemplo. Considerar:
Ahora, cuando tengas una buena idea de lo que significa un largo e int , entonces tanto el lanzamiento implícito de
int
tolong
como el lanzamiento explícito delong
toint
son bastante comprensibles. También es comprensible cómo se3
convierte3
y es solo otra forma de trabajar3
. Es comprensible cómo esto fallaráint.MaxValue + 1
en un contexto comprobado. Incluso cómo funcionaráint.MaxValue + 1
en un contexto no controlado para dar como resultadoint.MinValue
no es lo más difícil de asimilar.Del mismo modo, cuando realiza una conversión implícita a un tipo base o explícitamente a un tipo derivado, es comprensible para cualquiera que sepa cómo funciona la herencia lo que está sucediendo y cuál será el resultado (o cómo podría fallar).
Ahora, con BigObject y SmallObject no tengo idea de cómo funciona esta relación. Si sus tipos reales eran tales que la relación de lanzamiento era obvia, entonces el lanzamiento podría ser una buena idea, aunque muchas veces, tal vez la gran mayoría, si este es el caso, entonces debería reflejarse en la jerarquía de clases y bastará con una transmisión normal basada en la herencia.
fuente
BigObject
podrían describir unEmployee {Name, Vacation Days, Bank details, Access to different building floors etc.}
ySmallObject
podrían ser unMoneyTransferRecepient {Name, Bank details}
. Hay una traducción directa deEmployee
aMoneyTransferRecepient
, y no hay razón para enviar a la aplicación bancaria más datos de los necesarios.