Linee guida di progettazione per questo scenario in C #?

7

Devo creare un sistema di validazione (non voglio usare Data Annotation o qualsiasi altro sistema) per la mia applicazione C # usando .Net Compact Framework, dove ho un object che contiene molti altri oggetti.

Molte proprietà dipendono l'una dall'altra significa che hanno una sorta di dipendenza.

Posso scrivere una semplice classe validator che passa attraverso tutte le proprietà e li controlla uno ad uno con un sacco di if and else ma voglio progettare qualcosa di dinamico ad es. Dovrei essere in grado di specificare l'elenco delle dipendenze su una proprietà e specificare un metodo che dovrebbe essere invocato durante la convalida.

Voglio dire che alcune linee guida di progettazione sarebbero apprezzate?

Esempio (solo per scopi dimostrativi):

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

Nell'esempio sopra ho un MyBigObject che contiene alcune proprietà e alcuni altri oggetti e ho una classe storage che mantiene tutti i limiti delle proprietà che saranno richieste per convalidare una proprietà.

Come descritto nell'esempio precedente, devo ottenere ParameterInfo per ogni proprietà e quindi confrontare, sto cercando un modo automatico / dinamico per fare lo stesso.

    
posta Embedd_Khurja 04.02.2013 - 16:15
fonte

6 risposte

1
  1. Gli oggetti che contengono molti altri oggetti probabilmente stanno facendo troppe cose.
  2. Richiedere al programmatore di specificare le dipendenze li costringe a ripetersi, il che porterà a errori / incongruenze. Se riesci a trovare un modo per rilevare le dipendenze (staticamente o dinamicamente), sarebbe meglio.
  3. Avere un fascio di dipendenze mi preoccupa che le tue astrazioni non siano così pulite come dovrebbero essere. Le dipendenze tra le variabili dovrebbero (idealmente) essere isolate all'interno di una classe. Questo potrebbe non essere applicabile nel tuo caso, ma come linea guida - assicurati di aver davvero bisogno di un accoppiamento stretto tra le variabili in classi diverse.

E tutto ciò detto, la struttura compatta ha dovuto fare la convalida dell'input per sempre. Anche se le annotazioni di dati non sono supportate, è probabile che questo sia un problema risolto.

    
risposta data 04.02.2013 - 17:49
fonte
1

Che ne dici di estrarre la convalida e metterla allo stesso livello dell'input?

Quello che voglio dire è che non è il ruolo di un oggetto che si convalida . Un oggetto dovrebbe sempre essere valido: la creazione di uno non valido non ha molto senso. Allo stesso modo, non crei una persona con un'età di -50 , perché un'età è sempre un valore positivo o pari a zero.

Per garantire che un oggetto sia valido, uno utilizza contratti di codice in .NET Framework. Gli invarianti sarebbero particolarmente utili, dal momento che non solo impedirebbero di creare un oggetto non valido, ma anche di alterarne uno valido in modo che non fosse più valido. Allo stesso modo, i vincoli nei database impediscono l'archiviazione dei dati non validi.

Quindi, trovare un posto per la convalida dell'input dipenderà dal contesto. Se l'oggetto viene creato dall'input dell'utente (incluso, ad esempio, un'applicazione che utilizza la tua API), convalida l'input. Altre situazioni attenuerebbero la convalida da qualche altra parte. Se la creazione di un oggetto è un'attività difficile, verrà utilizzato uno factory , che descriverà come creare un oggetto, senza violare i suoi contratti.

    
risposta data 06.05.2013 - 13:59
fonte
1

Penso che ci sia un errore che stai facendo. E tu vuoi creare direttamente un framework / libreria. Per esempio. non si conoscono tutti i casi che questo framework / libreria deve risolvere, tuttavia, si sta tentando di creare questo framework / libreria.

Dovresti prima fare le cose direttamente, senza prima creare un quadro. Solo dopo aver creato più casi dovresti provare ad astrarre ciò che è comune tra quelle classi. Cercare di essere "dinamico" e "universale" ti farà solo del male a lungo andare.

Inoltre, il tuo esempio di codice sta urlando da un cattivo design OO. Nel momento in cui dai un enum "type" o "kind" (o "category" nel tuo caso), diventa ovvio che dovrebbero essere più classi diverse all'interno di una gerarchia. Questo è probabilmente il motivo per cui il tuo codice sembra così cattivo e "statico". Perché non ti importava della giusta separazione tra preoccupazioni e polimorfismo. Se lo facessi, potresti anche renderti conto che non hai bisogno di alcuna convalida dinamica e che la convalida con codice a mano va bene.

    
risposta data 03.08.2013 - 16:09
fonte
0

Bene, se vuoi liberarti di queste istruzioni switch è una buona idea usare il polimorfismo per convalidare gli oggetti (ad esempio rendendo MyBigClass una classe che è supertipo per le tue marche di veicoli).

I vantaggi di questo approccio sono:

  1. Puoi utilizzare l'invio dinamico per metodi come validare che sono astratti a MyBigClass Level e sono implementati nelle classi specifiche (Toyota, Mercedes, ...) che estendono MyBigClass
  2. Le regole per ciascun tipo di veicolo sono incapsulate
risposta data 21.05.2013 - 16:16
fonte
0

È possibile specificare un'interfaccia, ad esempio IValidatable e utilizzare reflection per scorrere tutte le proprietà e le proprietà secondarie e convalidare le eventuali implementazioni dell'interfaccia. È quindi necessario implementare Validazione su ogni piccola proprietà secondaria.

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

Questa è la radice del tuo problema però. Avere qualcosa che è difficile da validare è solo il sintomo. Il tuo miglior risultato è dividere la tua classe in componenti più piccoli e più gestibili.

    
risposta data 21.05.2013 - 16:25
fonte
0

Penso che tu voglia qualcosa come Fluent Validator per ASP MVC

L'idea è la stessa delle annotazioni, ma puoi definire regole in fase di runtime, anche se con meno "istruzioni if".

Ecco il codice di esempio del metodo di convalida:

[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);
    }
}
    
risposta data 03.08.2013 - 15:52
fonte

Leggi altre domande sui tag