2012-06-13 58 views
13

Por lo tanto, esta es realmente esta pregunta es mi piedra angular actual. Estoy trabajando en la refacturación de mi proyecto personal, tratando de aumentar el rendimiento, optimizar el uso de la memoria, hacer que el código sea fácil y claro. Tengo capas de aplicaciones diferentes (en realidad, DAL, BLL, ServiceAgents que son servicios de WCF). Estoy usando Entidades/Modelos/DTO para pasar datos entre esas capas, que es sin estado (no tiene ninguna lógica en absoluto). Actualmente este es un objeto de este tipoDTO classes vs. struct

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

Solía ​​usar este enfoque, es como una "mejor práctica", ¿verdad? ¿Es esta la mejor manera de almacenar datos transferidos? ¿Y si lo cambio por estructura así:

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

¿Es esto sería mejor modo de rendimiento/memoria perspectiva de uso? ¿O tal vez hay algún tipo de trampas actuando de esa manera?

+2

"clase" (que fue fácil; p) –

+0

¡Gracias a todos por participar! –

Respuesta

14

Para las entidades DTO estándar, querrá seguir con la clase.

A struct tiene un alcance mucho más limitado que las clases. También hay problemas de eficiencia cuando los tipos struct se vuelven demasiado grandes (no olvide, son tipos de valores y son copiados cuando se pasan), como se describe en el MSDN guidelines about value types. Por no hablar de un montón de trampas cuando empieza a tener struct tipos expuestos a través de propiedades, o accidentalmente caja en la que al hacer referencia a las interfaces, como si los hace mutable ...

No estoy saying not to usestruct cuando es relevante, pero muy rara vez me veo en la necesidad de utilizar los tipos struct en nuestra aplicación de escritorio principal, que tiene capas y ofrece tipos de DTO.


El problema de rendimiento no se puede responder tan simplemente como struct frente a class. Tendrá que emplear una herramienta de creación de perfiles como dotTrace o ANTS para encontrar los puntos de acceso e ir desde allí. Los problemas de rendimiento no son triviales y una buena herramienta suele ser el comienzo de la respuesta.

+1

+1. Una adición: [¡Las estructuras mutables son MALAS!] (Http://stackoverflow.com/questions/441309/why-are-mutable-structs-evil) – Steven

+0

@Steven Por supuesto, agregué ese enlace en mi respuesta - tipo de subliminal ;-) –

+0

De acuerdo. Para aliviar algunos dolores de cabeza que rodean la copia de valores hacia y desde estos objetos, apalanque [AutoMapper] (automapper.org). – bluevector

4

¿Sería mejor desde la perspectiva del rendimiento/uso de la memoria?

No. Las estructuras son tipos de valores, por lo que se copian por su valor. Esto significa que en lugar de copiar solo una referencia, siempre copiará el objeto completo. En todo caso, probablemente sea un poco más lento y use más memoria (ya que el objeto se duplicará).

Otra razón por la que no debes hacer esto: las estructuras mutables siempre se deben evitar, ya que pueden provocar un comportamiento inesperado si no tienes cuidado.

2

A struct puede ser más peligroso si el CLR maneja los tipos de valores de forma mucho más diferente y si se escribe mal (por ejemplo, una estructura mutable) puede crear terribles dolores de cabeza. Además, si su tipo contiene muchos campos y luego se pasa de método a método, copiará el valor de cada campo en cada método llame al y, por lo tanto, use más memoria que si hubiera utilizado una clase en primer lugar.

El uso de DTO (objetos de transferencia de datos) que fomentaría la separación de estado y comportamiento. Esto puede ser un buen diseño si se realiza correctamente (y en la mayoría de los casos implementaría este patrón usando clases, no estructuras).

Además, el caso específico de usar struct como DTO object parece defectuoso, porque introduce innecesaria redundancy. Desde el structs cannot inherit other structs, no puede expresar las relaciones is-a. ¿Qué haces cuando tienes Customer que hereda de Person. ¿Repite todo el Person properties in the Customer struct? ¿Anida una Estructura de persona dentro de una estructura de Cliente? Ninguno de los enfoques es ideal. Si al menos utilizó las clases, , puede solicitar al cliente que extienda la Persona.

1

Debe utilizar el enfoque de clase, el enfoque de estructura podría ser incluso más lento ya que las estructuras son tipos de valores y las copias se realizarán donde quiera que las pase como parámetros de función. Entonces, para que sus DTO se apeguen al enfoque de clase.

0

Mi opinión es: las clases son mejores.

Con las clases puede implementar la interfaz INotifyPropertyChanged, lo que será muy útil si realiza el enlace de datos.

También puede tener algunos campos privados como "ID" solo con "get" -property, puede agregar algunos métodos a su clase, puede hacer que sus entidades sean serializables.
Todo lo que quiero decir es que eres más flexible con las clases, y no creo que exista una gran diferencia de rendimiento entre la estructura y las clases en ese caso.

Aquí es un muy buen libro que me ha ayudado mucho diseñando-aplicaciones nTier: http://msdn.microsoft.com/en-us/library/ee817644.aspx

Tome una mirada allí. Dice: "Elegir entre estructuras y clases. Para las entidades comerciales simples que no contienen contener datos jerárquicos o colecciones, considere definir una estructura para representar la entidad comercial. Para entidades comerciales complejas, o para entidades comerciales que requieren herencia, define la entidad como una clase en su lugar ".

+0

Estoy usando clases sin estado: sé de INotifyPropertyChanged pero según mi tarea no lo necesito. Tampoco necesito agregar ninguna lógica (métodos) a estos objetos. Y las propiedades de solo obtener: struct puede tener campos de solo lectura, ¿no? –

+0

sí, tienes razón. Lo siento por el mal ejemplo. – sickUnit

5

Las dos mejores opciones para un objeto de transferencia de datos generalmente deben ser un objeto de clase profundamente inmutable o una estructura con campos expuestos de tipos adecuados para su uso como objetos de transferencia de datos. También se pueden usar otros tipos de estructuras, pero las estructuras de campo expuesto son de lejos las más simples, y esa simplicidad es una gran virtud.

La noción de que estructuras mutables son las fechas del mal de nuevo a algunos de los primeros C# Compiladores la que en la que

 
    SomeReadonlyStruct.SomeProperty = 5; 

estaría en silencio transformar por el compilador en:

 
    var temp = SomeReadonlyStruct; 
    temp.SomeProperty = 5; 

Ocultación campos struct detrás de propiedades de sólo lectura fue un intento de asegurar que la declaración anterior se negara a compilar en lugar de producir código roto. Debido a que los compiladores más nuevos se negarán a mutar campos escribibles de estructuras de solo lectura, ya no es necesario ajustar los campos en propiedades de solo lectura.

Las estructuras con campos expuestos tienen una gran ventaja comparadas con otros tipos de objetos de transferencia de datos: cada estructura que tiene campos expuestos de tipos adecuados para transferencia de datos y ningún otro miembro excepto tal vez un constructor se comporta de la misma manera, sin sorpresas Alguien que nunca ha usado las estructuras podría estar un poco sorprendido por el hecho de que no actúan como clases, pero alguien que entienda cómo funciona una estructura así entenderá cómo funcionan todas.

considere el siguiente código:

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

Algunas personas no les gusta el hecho de que si customerPhone es una estructura de campo expuesta, estableciendo la propiedad Extension no afectará a la información en someDataSource. Si bien es cierto que escribir un campo de estructura no actualizará nada más, esa es una situación mucho mejor de la que existiría si customerPhone fuera un tipo de clase mutable. Cualquiera que entienda que customerPhone es un tipo de estructura de campo expuesto sabrá que los cambios en sus miembros no afectarán a nada más. Por el contrario, si customerPhone es un tipo de clase mutable, el código como el anterior puede actualizar someDataSource cambiando el número de teléfono asociado con ese customerID. O tal vez no. O bien, si un número de teléfono se asoció con dos valores de customerID, el código anterior podría cambiarlos a ambos. La cantidad de código que uno debe estudiar para determinar exactamente qué efectos y efectos secundarios podría tener el código anterior sería bastante grande. Peor aún, puede ser difícil estar seguro de que uno no se haya perdido nada.

Definitivamente, hay algunos lugares donde pasar referencias de objetos de clase puede ser más eficiente que pasar estructuras. También hay unos pocos casos donde los objetos de clase mutables pueden ser portadores de datos útiles dentro de una clase. Algunos contenedores genéricos, sin embargo, pueden faclitate envolviendo una estructura en una clase mutable o inmutable, e intercambiando la información entre esos tipos de clases.

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

Tal construcción sería mucho más incómoda sin estructuras mutables.