Objetos DTO en C#

Los objetos de trasferencia de datos (DTO) pueden ser de mucha utilidad al momento de desarrollar software. Basicamente son un molde para la información, donde el esquema se encuentra fuertemente tipeado
Algunas de las ventajas de utilizar diseños que implementen este tipo de objetos son:

  • En cualquier punto del sistema la información puede ser validada, a partir de metadatos establecidos
  • Mejora la comunicación entre los programadores, dandoles un mismo esquema de información, evitando conflictos
  • Separa fisicamente las capas del sistema, haciendo el codigo mucho mas limpio y reutilizable
  • Proporciona mayor seguridad

Aunque estos objetos pueden darnos una gran cantidad de ventajas, tienen una enorme desventaja la cual es la causante de su poco uso, y es el tiempo de desarrollo, ya que obliga al programador a tipear cada una de las entidades logicas del sistema.
Es por esta razón por la cual muchas de las compañias que utilizan este tipo de diseño, o que elaboración frameworks para lo mismo, utilizan herramientas de generación automatica de código.

En lo que respecta a .NET, Microsoft deposito toda su confianza en los famosos objetos denominados Dataset, con los cuales se puede trabajar de una manera muy grafica y sencilla, es muy facil crear un esquma de información a partir de una base de datos de casi cualquier tipo (SQL, OLEDB, XML, etc.).
Pero estos objetos Dataset tienen una desventaja tan grande como sus ventajas… no les importa el diseño del sistema, puedes continuar utilizando los asistentes del VS y ver como terminas juntando el acceso a datos, juntos con las reglas de negocio y la interfaz grafica, tienen tanta funcionalidad que resulta practicamente inutil tratar de heredarlos e incrementar funcionalidad.

Aunque es posible crear objetos DTO usando un Dataset, muchas veces resulta inapropiado, ya que se perdio la razón de ser de estos mismos que es: asegurarse que el transporte de la información se lleve acabo de manera practica y segura, y solo eso.Es por eso que me decidi a crear mi propia estructura para objetos DTO, la cual aunque muy simple tambien es muy concreta y eficaz.
Aún no acabo de hacer todo lo que eh querido (una aplicación de auto-generación de código, y la funcionalidad de serialización en XML), pero por lo pronto ya tiene la funcionalidad que deberia tener para poder trabajar con el.

Les muestro el diagrama de clases, y el código, si alguien tiene alguna de idea de alguna modificación, escribanlo en los comentarios


DTO Class Diagram

using System;
using System.Collections.Generic;

    /// <summary>
    /// Domain. Representa la gama de valores en que cierto objeto debe pertenecer
    /// </summary>
    public struct Range<type> where type : struct
    {

        #region Campos
            private System.Nullable<type> minValue;
            private System.Nullable<type> maxValue;
            private bool applyMinValue;
            private bool applyMaxValue;
        #endregion

        #region Constructores

            internal Range(System.Nullable<type> minValue, System.Nullable<type> maxValue) {
                this.minValue = minValue;
                this.maxValue = maxValue;
                this.applyMinValue = true;
                this.applyMaxValue = true;
            }

            internal Range(System.Nullable<type> minValue, System.Nullable<type> maxValue, bool applyMinValue, bool applyMaxValue)
            {
                this.minValue = minValue;
                this.maxValue = maxValue;
                this.applyMinValue = applyMinValue;
                this.applyMaxValue = applyMaxValue;
            }            

        #endregion

        #region Propiedades
            public object MinValue {
                get { return minValue; }
            }
            public object MaxValue {
                get { return maxValue; }
            }
            public bool ApplyMinValue {
                get { return applyMinValue; }
            }
            public bool ApplyMaxValue {
                get { return applyMaxValue; }
            }
        #endregion

    }

    /// <summary>
    /// Metada. Representa un metadato (Información de un campo)
    /// </summary>
    public class MetaData
    {

        #region Campos

            private Type netType; //Default. NETTypes.String
            private int length; //Default. 0
            private int maxLength; //Default. 0

            private bool isNullable; //Default. false
            private bool isReadOnly; //Default. false
            private bool isUnique; //Default. false

            private int numericPrecision; //Default. 0
            private int numericScale; //Default. 0

        #endregion

        #region Constructores

            /// <summary>
            /// MetaData. Constructor Generico
            /// </summary>
            public MetaData() {
                this.netType = Type.GetType("System.String");
                this.length = 0;
                this.isNullable = false;
                this.isReadOnly = false;
                this.isUnique = false;
                this.numericPrecision = 0;
                this.numericScale = 0;
            }
            /// <summary>
            /// Metadata. Constructor por tipo
            /// </summary>
            public MetaData(Type nettype) : this(){
                this.netType = nettype;
            }

        #endregion

        #region Propiedades

            public Type NetType {
                get {
                    return this.netType;
                }
                set {
                    this.netType = value;
                }
            }

            public int Length {
                get {
                    return this.length;
                }
                set {
                    this.length = value;
                }
            }

            public int MaxLength{
                get {
                    return this.maxLength;
                }
                set {
                    this.maxLength = value;
                }
            }

            public bool IsNullable {
                get {
                    return this.isNullable;
                }
                set{
                    this.isNullable = value;
                }
            }

            public bool IsReadOnly {
                get {
                    return this.isReadOnly;
                }
                set {
                    this.isReadOnly = value;
                }
            }

            public bool IsUnique {
                get {
                    return this.isUnique;
                }
                set {
                    this.isUnique = value;
                }
            }

            public int NumericPrecision {
                get {
                    return this.numericPrecision;
                }
                set {
                    this.numericPrecision = value;
                }
            }

            public int NumericScale {
                get {
                    return this.numericScale;
                }
                set {
                    this.numericScale = value;
                }
            }

        #endregion

    }

    /// <summary>
    /// FieldMeta. Clase abstracta basica de Field
    /// </summary>
    public abstract class BaseField : MarshalByRefObject
    {

        #region Campos

            private MetaData meta;
            private string name;

        #endregion

        #region Constructores

            public BaseField(string name, MetaData meta) {;
                this.name = name;
                this.meta = meta;
            }

            public BaseField(string name, MetaData meta, bool isLocked){
                this.name = name;
                this.meta = meta;
            }            

        #endregion

        #region Propiedades

            internal MetaData Meta{
                get { return this.meta; }
                set { this.meta = value; }
            }

            public string Name{
                get { return name; }
                set { name = value; }
            }

        #endregion

        #region Delegados & Eventos

            internal delegate void ValueChange(BaseField field, object value);
            internal event ValueChange valueChange;

            internal void OnValueChange(BaseField field, object value) {
                if (valueChange != null) {
                    valueChange(field, value);
                }
            }
        #endregion
    }

    /// <summary>
    /// Field. Representa un campo
    /// </summary>
    public class Field<type> :  BaseField where type : struct
    {

        #region Campos
            private System.Nullable<type> value;
            private System.Nullable<Range<type>> range;
            private string regEx;
        #endregion

        #region Constructores

            public Field(string name, MetaData meta) : base(name, meta) { }
            public Field(string name, MetaData meta, bool isLocked) : base(name, meta, isLocked) { }

        #endregion

        #region Propiedades

            public type Value{
                get { return this.value.Value; }
                set {  this.value = value; }
            }

            public Range<type> Range {
                get { return this.range.Value; }
                set { this.range = value; }
            }

            public string RegEx {
                get { return this.regEx; }
                set { this.regEx = value; }
            }

            public bool HasValue {
                get { return value.HasValue; }
            }

            public bool HasRange{
                get { return range.HasValue; }
            }

            public bool HasRegEx {
                get { return !string.IsNullOrEmpty(this.regEx); }
            }

        #endregion

        #region Metodos

            #region General

                public override string ToString() {
                    if (value.HasValue){
                        return Value.ToString();
                    }
                    else{
                        return string.Empty;
                    }
                }                

            #endregion

            #region Dominio

                public void SetRange(type minValue, type maxValue)
                {
                    this.range = new Range<type>(minValue, maxValue);
                }

                public void SetRange(type minValue, type maxValue, bool applyMinValue, bool applyMaxValue)
                {
                    this.range = new Range<type>(minValue, maxValue, applyMinValue, applyMaxValue);
                }

            #endregion 

        #endregion

    }

    /// <summary>
    /// DTObject. Representaun objeto tipo DTO
    /// </summary>
    public abstract class DTObject : MarshalByRefObject
    {

        #region Campos
            private Dictionary<string, BaseField> internalCollection;
        #endregion

        #region Propiedades
            public BaseField this[string name]{
                get { return this.internalCollection[name]; }
            }
        #endregion

        #region Constructores
            public DTObject() {
                this.internalCollection = new Dictionary<string,BaseField>();
                SetFields();
            }
        #endregion

        #region Metodos
            protected abstract void SetFields();
            protected void AddField(string name, BaseField field) {
                field.valueChange += new BaseField.ValueChange(OnValueChange);
                this.internalCollection.Add(name, field);
            }
        #endregion

        #region Delegados & Eventos
            public delegate void ValueChange(BaseField field, object value);
            public event ValueChange fieldValueChange;

            protected void OnValueChange(BaseField field, object value){
                if (fieldValueChange != null){
                    fieldValueChange(field, value);
                }
            }
        #endregion
    }
Payton Boyd says:

Is anyone aware if there is as cheap pro reputation service than ReputationUP.com? AmerisourceBergen? They only cost 49 dollars which is not much, unfortunately my co-worker Christopher said me there is, unfortunately he could not remember its name. 1 indeed start to get feeling that he recalled wrongly. Please reply