¿Directrices de diseño para este escenario en C #?

7

Tengo que crear un sistema de validación (no quiero usar Anotación de datos o cualquier otro sistema) para mi aplicación C # usando .Net Compact Framework, donde tengo un object que contiene muchos otros objetos.

Muchas de las propiedades dependen entre sí significa que tienen algún tipo de dependencias.

Puedo escribir una clase simple validator que pasa por todas las propiedades y los verifica uno por uno con un montón de if and else pero quiero diseñar algo dinámico, por ejemplo. Debería poder especificar la lista de dependencias en una propiedad y especificar un método que debería invocarse durante la validación.

Quiero decir, ¿se apreciarían algunas pautas de diseño?

Ejemplo (solo para fines de demostración):

    public enum Category
        {
            Toyota,
            Mercedes,
            Tata,
            Maruti
        }

        class MyBigClass
        {
            public Category Category { get; set; }
            public double LowerPrice { get; set; }
            public double UpperPrice { get; set; }

            public SomeOtherObject OtherObject { get; set; }

public List<string> Validate()
        {
            List<string> listErrors = new List<string>();
            ParameterInfo pInfo = null;
            switch (Category)
            {
                case Category.Toyota:
                    pInfo = ParameterStorage.GetParameterInfo(PTYPE.Category_Toyota);
                    break;
                case Category.Mercedes:
                    pInfo = ParameterStorage.GetParameterInfo(PTYPE.Category_Mercedes);
                    break;
                case Category.Tata:
                    pInfo = ParameterStorage.GetParameterInfo(PTYPE.Category_Tata);
                    break;
                case Category.Maruti:
                    pInfo = ParameterStorage.GetParameterInfo(PTYPE.Category_Maruti);
                    break;
                default:
                    break;
            }

            if (LowerPrice < pInfo.Min || LowerPrice >= pInfo.Max)
            {
                listErrors.Add("LowerPrice");
            }

            if (UpperPrice > pInfo.Max || UpperPrice <= pInfo.Min)
            {
                listErrors.Add("UpperPrice");
            }

            return listErrors;
        }
        } 

        public enum PTYPE
            {
                RATING,
                Category_Tata,
                Category_Toyota,
                Category_Mercedes,
                Category_Maruti
            }

            public class ParameterInfo
            {
                public PTYPE Type { get; set; }
                public int Min { get; set; }
                public int Max { get; set; }
                public int Default { get; set; }
            }

       public class ParameterStorage
        {
            private static Dictionary<PTYPE, ParameterInfo> _storage = new Dictionary<PTYPE, ParameterInfo>();
            static ParameterStorage()
            {
                _storage.Add(PTYPE.Category_Maruti, new ParameterInfo { Type = PTYPE.Category_Maruti, Min = 50000, Max = 200000 });
                _storage.Add(PTYPE.Category_Mercedes, new ParameterInfo { Type = PTYPE.Category_Mercedes, Min = 50000, Max = 800000 });
                _storage.Add(PTYPE.Category_Toyota, new ParameterInfo { Type = PTYPE.Category_Toyota, Min = 50000, Max = 700000 });
                _storage.Add(PTYPE.Category_Tata, new ParameterInfo { Type = PTYPE.Category_Tata, Min = 50000, Max = 500000 });
            }

            public static ParameterInfo GetParameterInfo(PTYPE type)
            {
                ParameterInfo pInfo = null;
                _storage.TryGetValue(type, out pInfo);
                return pInfo;
            }
        }

En el ejemplo anterior, tengo un MyBigObject que contiene algunas propiedades y algunos otros objetos y tengo una clase storage que mantiene todos los límites de propiedades que serán necesarios para validar una propiedad.

Como se describe en el ejemplo anterior, tengo que obtener ParameterInfo para cada propiedad y luego comparar, estoy buscando algún tipo de forma automática / dinámica de hacer lo mismo.

    
pregunta Embedd_Khurja 04.02.2013 - 16:15

6 respuestas

1
  1. Los objetos que contienen muchos otros objetos probablemente están haciendo demasiadas cosas.
  2. Exigir que el programador especifique las dependencias los obliga a repetirse, lo que dará lugar a errores / inconsistencias. Si puedes encontrar una manera de detectar dependencias (estática o dinámicamente), eso sería mejor.
  3. Tener un paquete de dependencias hace que me preocupe que sus abstracciones no sean tan limpias como deberían ser. Las dependencias entre variables deberían (idealmente) estar aisladas dentro de una clase. Es posible que esto no se aplique a su caso, pero como una guía, asegúrese de que realmente necesita ese acoplamiento estrecho entre variables en diferentes clases.

Y todo lo dicho, el marco compacto ha tenido que hacer validación de entrada para siempre. Incluso si las anotaciones de datos no son compatibles, es probable que este sea un problema resuelto.

    
respondido por el Telastyn 04.02.2013 - 17:49
1

¿Qué hay de extraer la validación y colocarla en el mismo nivel que la entrada?

Lo que quiero decir es que no es la función de un objeto validarse a sí mismo . Un objeto siempre debe ser válido: crear uno inválido no tiene mucho sentido. De la misma manera, no creas una persona con una edad de -50 , porque una edad siempre es un valor positivo o cero.

Para garantizar que un objeto sea válido, uno usa Contratos de código en .NET Framework. Invariantes sería especialmente útil, ya que no solo evitarían la creación de un objeto no válido, sino que también alterarían uno válido para que no sea válido. De la misma manera, las restricciones en las bases de datos impiden que se almacenen datos no válidos.

Entonces, encontrar un lugar para la validación de entrada dependerá del contexto. Si el objeto se crea a partir de la entrada del usuario (incluida, por ejemplo, una aplicación que utiliza su API), valide la entrada. Otras situaciones mitigarían la validación en otro lugar. Si crear un objeto es una tarea difícil, uno usará una fábrica , que explicará cómo crear un objeto, sin violar sus contratos.

    
respondido por el Arseni Mourzenko 06.05.2013 - 13:59
1

Creo que hay un error que estás cometiendo. Y eso es lo que desea crear un marco / biblioteca directamente. P.ej. no conoce todos los casos que este marco / biblioteca necesita resolver, sin embargo, está intentando crear este marco / biblioteca.

Primero debes hacer las cosas directamente, sin hacer primero un marco. Solo después de crear varios casos, debe tratar de abstraer lo que es común entre esas clases. Tratar de ser "dinámico" y "universal" solo le hará daño a largo plazo.

Además, su ejemplo de código está gritando por un mal diseño de OO. En el momento en que nombra una enumeración "tipo" o "tipo" (o "categoría" en su caso), se vuelve obvio que deben ser múltiples clases diferentes dentro de una jerarquía. Probablemente esta sea la razón por la que su código se ve tan mal y estático. Porque no te importó la separación adecuada de preocupaciones y el polimorfismo. Si hizo esto, incluso podría darse cuenta de que no necesita ninguna validación dinámica y que la validación codificada a mano está bien.

    
respondido por el Euphoric 03.08.2013 - 16:09
0

Bueno, si desea deshacerse de esas declaraciones de cambio, es una buena idea usar el polimorfismo para validar objetos (por ejemplo, hacer de MyBigClass una clase que sea supertipo para las marcas de sus vehículos).

Los beneficios de este enfoque son:

  1. Puede utilizar el envío dinámico para métodos como validate que son abstractos en MyBigClass Level y se implementan en las clases específicas (Toyota, Mercedes, ...) que extienden MyBigClass
  2. Las reglas para cada tipo de vehículo están encapsuladas
respondido por el McMannus 21.05.2013 - 16:16
0

Podría especificar una interfaz, digamos IValidatable y usar la reflexión para recorrer todas las propiedades y sub propiedades y validar cualquiera que implemente la interfaz. Entonces, solo necesita implementar Validar en cada sub propiedad pequeña.

Many of the properties are dependent on each other means they have some sort of dependencies.

Aunque esta es la raíz de tu problema. Tener algo que es difícil de validar es solo el síntoma. Lo mejor es dividir su clase en componentes más pequeños y más manejables.

    
respondido por el Tom Squires 21.05.2013 - 16:25
0

Creo que quieres algo como esto Fluent Validator para ASP MVC

La idea es la misma que con las anotaciones, pero puede definir reglas en tiempo de ejecución, aunque con mucho menos "if-statement".

Aquí está el código de ejemplo del método de validación:

[Validator(typeof(PersonValidator))]
public class Person {
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public int Age { get; set; }
}

public class PersonValidator : AbstractValidator<Person> {
    public PersonValidator() {
        RuleFor(x => x.Id).NotNull();
        RuleFor(x => x.Name).Length(0, 10);
        RuleFor(x => x.Email).EmailAddress();
        RuleFor(x => x.Age).InclusiveBetween(18, 60);
    }
}
    
respondido por el Antonio 03.08.2013 - 15:52

Lea otras preguntas en las etiquetas