Ho bisogno di un consiglio Architetturale --- nella domanda che segui non
date quindi il valore giusto(nel mondo .net) alle parole
attributo/proprietà/decorato/...ecc..ec.. in quanto sarebbero fuorvianti....
Mi serve appunto un consiglio su come gestire tali necessità attribuendo un
valore generale (in italiano) alle parole usate...
Devo realizzare delle classi che contengono una serie di campi(propietà)
prestabiliti:
Class MyClass
Field1 as string
field2 as int
field3 as MyTipe
End class
Ogni campo/proprietà deve poter essere "decorato" da alcune
proprieta/attributi che ne identificano un certo comportamento.
Per esempio
field1 potrebbe essere decorato con una (o più di queste proprietà)
1)required
2)required, default
3)required not default
4)fixedvalue
5)ignored
6)reserved
...
..
ecc
ecc.
In seguito,
A run-time ho bisogno di scoprire se quel campo è decorato da una u più di
tali proprieta e ottenerle.
Ed inoltre a seconda della proprietà voglio recuperare un valore specifico
che la rappresenta...
esempio :
scopro che field1 è di tipo required,default a questo punto voglio sapere
anche quale è il valore di default:
field1 ---> requireddefault ---> defaultvalue=4
grazie tante
Marco
You wrote :
>
> field1 ---> requireddefault ---> defaultvalue=4
>
la risposta sono gli attributi e un po' di sana reflection, per gli
attributi custom ti basta realizzare una classe che deriva da Attribute
e il gioco è fatto.
Faccio io una domanda: stai pensando ad un sistema di validazione?
.m
--
Mauro Servienti
Microsoft MVP - Visual C# / MCP
http://mvp.support.microsoft.com
http://blogs.ugidotnet.org/topics
whynot [ at ] topics [ dot ] it
La spiegazione è piuttosto lunga.
In sostanza si applica il principio dell'Inversion Of Control,
per cui la validazione non si fa tramite attributi ed inoltre si delega la
validazione
ad una classe esterna, per non creare dipendenze.
Se il metodo che valida fosse definito internamente alla classe
e fosse basato su attributi, sarebbe necessario ricompilare
l'applicazione ogni volta che si cambia la logica di validazione.
In più si lega il concetto di valido alla definizione della classe,
rendendola difficilmente utilizzabile in scenari differenti.
Per una spiagazione più completa di questa metodologia
ti rimando a questo articolo:
http://martinfowler.com/articles/injection.html.
Dovrei inoltre implementare questo sistema in un'applicazione
open che stò sviluppando.
Se hai altri dubbi chiedi pure! :-).
Mi scuso per la lunghezza, ma con meno codice non sarebbe possibile
spiegare i concetti.
Qui l'esempio:
--------------------------------------------
''' <summary>
''' Represents a validable entity.
''' </summary>
Public Interface IValidableEntity
Function IsValid() As Boolean
End Interface
''' <summary>
''' Represents a validator.
''' </summary>
Public Interface IEntityValidator
Function IsValid(Of T)(ByVal item As Object) As Boolean
End Interface
''' <summary>
''' Represents a concrete hard coded validator.
''' </summary>
Public Class FooValidator
Implements IEntityValidator
#Region "IEntityValidator Members"
Public Function IsValid(Of T)(ByVal item As Object) As Boolean Implements
IEntityValidator.IsValid
If GetType(T) Is GetType(Person) Then
Dim person As Person = CType(item, Person)
Return ((Not String.IsNullOrEmpty(person.Name)))
Else
Throw New NotSupportedException()
End If
End Function
#End Region
End Class
''' <summary>
''' Returns a concrete validator using a particular logic.
''' </summary>
Public Class ValidatorFactory
Private Sub New()
End Sub
Public Shared Function GetValidator(Of T)() As IEntityValidator
If GetType(T) Is GetType(Person) Then
Return New FooValidator()
Else
Throw New NotSupportedException()
End If
End Function
End Class
''' <summary>
''' Represents a person.
''' </summary>
Public Class Person : Implements IValidableEntity
Private _name As String
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
Public Function IsValid() As Boolean Implements IValidableEntity.IsValid
Return ValidatorFactory.GetValidator(Of Person)().IsValid(Of Person)(Me)
End Function
End Class
--------------------------------------------
--
Matteo Migliore
Blog - http://blogs.ugidotnet.org/matteomigliore
Mauro, scusa la doppia risposta, ma l'avevo già pronta,
avevo dimenticato di inviarla :-P.
Ciao!!
non ho le idee chiare su cosa intendi....
mi ricordo che hanni fa circolava la Janky Validation....una sera quando ne
parlavano in macchina Janky e Lorenzo ...c'ero sentivo che ne parlavano ma
non ho mai capito di cosa si trattasse! centra qualcosa?
Comunque sia; se rispondessi : Sì! cosa hai da propormi?
ciao e grazie.
marco b
marco b
"Matteo Migliore" <matteo.mi...@gmail.com> ha scritto nel messaggio
news:%23N18E76...@TK2MSFTNGP04.phx.gbl...
comunque dal tuo esempio ho:
una intefaccia: IValidableEntity (implementata da person)
una intefaccia: IEntityValidator (implementata da FooValidator)
una classe: person
una classe: FooValidator
una classe:ValidatorFactory
Immagino che il client:
0)istanzi una classe person e chiami isvalid che richiama la
validatorfactory
1)la ValidatorFactory chiami GetValidator(passando il tipo necessario -
person in questo caso)
2)il metodo ritorna una FooValidator (che espone l'interfaccia
IEntityValidator e quindi il metodoIsValid)
3)a questo punto viene verificata la validità hard coded in FooValidator
Se ho capito la logica, ti chiedo comunque di darmene la motivazione di
questo "rigirio" in quanto non capisco la necessità.
In particolora la presenza di FooValidator e ValidatorFactory che entrambi
devono conoscere il tipo Person.
......
Tirnando al mio caso io ho necessità di valutare la validità non di una
intera classe ma solo dei suoi campi singolarmente.
E ogni campo lo devo distiguere da un'altro tramite un qualche sistema di
demarcazione
in quanto potrei avere 3 campi string che ovviamente si chiamano
diversamente ma uno lo voglio validare con una regola perche per esempio
deve essere una string di una lunghezza fissata
mentre l'altro campo deve essere una stringa di lunghezza arbitraria....o
ancora più difficile...deve poter avere un valore di default...
Cosa posso fare.?
grazie
ciao marco b
You wrote :
>> Faccio io una domanda: stai pensando ad un sistema di validazione?
>
> Comunque sia; se rispondessi : Sì! cosa hai da propormi?
>
che io personalmente non condivido la scelta di design di piazzare le
regole per la validazione su una classe scolpendole nella pietra troppo
restrittivo, IMVHO.
> ciao e grazie.
>
> marco b
.m
Puoi spiegarti meglio perfavore non ti seguo in quanto non conosco queste
metodologie.
Dopo alcune letture sono arrivato a Spring.Net , ritieni che sia una
soluzione al mio problema?
Solo che dovre implementare un framework di cui non conosco niente.
Esiste un sistema per risolvere il mio problema in modo elegante senza
andare a complicare le cose?
ciao grazie.
marco
Sprint.NET è un framework che tra le altre cose
fornisce supporto al pattern Inversion Of Control (IoC).
Non è necessario però adottare un toolkit esterno
per risolvere problemi semplici. E' utile in applicazioni
che gestiscono pesantemente le funzionalità tramite
file di configurazione.
Nell'esempio che ho fatto, la classe ValidatorFactory
restituisce la classe concreta che esegue la validazione
istanziandola direttamente. E' ovviamente possibile invece
scrivere in un file di configurazione (app.config) quale classe
istanziare per eseguire la validazione per ogni tipo gestito.
In questo modo è possibile sostituire la classe che esegue
la validazione semplicemente modificando il file di configurazione,
e cambiare eventualmente la logica di validazione.
E' inoltre possibile scrivere un file XML di mapping
(simile ai file hbm.xml di NHibernate) in cui definire
per ogni property i validatori da applicare anzichè
cablarli nel codice della classe.
Esempio:
----------------------------------------
<validableEntity name="Person">
<property name="Name">
<validator type="RequiredValidator" value="true" />
<validator type="MinLenghtValidator" value="10" />
</property>
<property name="Age">
<validator type="RequiredValidator" value="false" />
<validator type="MinDateValidator" value="01/01/1980" />
</property>
</validableEntity>
----------------------------------------
Quindi la classe FooValidator potrebbe leggere queste
informazioni dal file XML e istanziare i validatori
per ogni property e richiamarli.
> Solo che dovre implementare un framework di cui non conosco niente.
> Esiste un sistema per risolvere il mio problema in modo elegante senza
> andare a complicare le cose?
Puoi partire dall'esempio che ho fatto.
Una volta capito quello puoi passare a qualcosa di
più sofisticato.
> ciao grazie.
Prego! ;-)
--
Matteo Migliore
Blog: http://blogs.ugidotnet.org/matteomigliore
Sei sicuro che dovrebbe essere FooValidator a doverlo fare?
A me sembra più logico che sia ValidatorFactory a recupera il file xml ed in
base al tipo chiamante passarre l'ooportuno foovalidator
dove sbaglio?
ciao
grazie.
m b
Sě, abbastanza sicuro :-D.
> A me sembra piů logico che sia ValidatorFactory a recupera il file xml ed
> in base al tipo chiamante passarre l'ooportuno foovalidator
>
> dove sbaglio?
FooValidator potrebbe essere rinominato in
XmlMappingValidator, poi potresti avere un HardCodeValidator
etc... ValidatorFactory č solamente la classe che ritorna
il validator concreto.
Qui ho pubblicato una semplice solution,
forse si capisce meglio:
http://www.codeplex.com/ValidationInverse
La solution si trova sotto la sezione "Source Code".
Purtroppo č in C#, ma online si trovano
decine di tool per la conversione.
grazie per adesso.
Marco B
"Matteo Migliore" <matteo.mi...@gmail.com> ha scritto nel messaggio
news:%2398lE7H...@TK2MSFTNGP06.phx.gbl...
Ti chiedo cortesemente di darmi una spiegazione a voce (scritta in italiano)
delle fasi e soprattutto del perchè
infatti nonostante capisca le chiamate e tutto ciò che succede mi sfugge il
significato di tutti quei passaggi e chiamate di interfaccia.
grazie
ciao
marco
Ci riprovo :-).
La classe statica ValidationFactory restituisce una factory
che restituisce un validatore concreto (HardCodedValidator o XmlValidator).
Il validator concreto può essere selezionato specificandolo dal
file di configurazione. La classe Person che implementa
il metodo di validazione IsValid *non* conosce la classe
concreta che si occuperà della validazione.
Questo consente di cambiare il metodo di validazione
senza modificare la classe Person, consentendo
inoltre di cambiare la logica di validazione
a seconda dello scenario o del contesto di utilizzo
di Person.
E' più chiaro?
Se hai pazienza implemento anche una versione
che consente di specificare i validatori
via XML.
> grazie
You wrote :
> Ti chiedo cortesemente di darmi una spiegazione a voce (scritta in italiano)
> delle fasi e soprattutto del perchè
> infatti nonostante capisca le chiamate e tutto ciò che succede mi sfugge il
> significato di tutti quei passaggi e chiamate di interfaccia.
>
marco nonostante l'esempio di Matteo sia più che corretto e decisamente
semplice se non hai mai avuto necessità di IoC (Inversion of Control) e
non hai idea di filosoficamente cosa sia anche quell'esempio è uno
scoglio difficilmente superabile, soprattutto perchè mi sembra che il
tuo scopo sia giustamente quello di capire e non solo pedissequamente
applicare. Detto questo, vediamo di capire il problema:
Il problema in qualsiasi contesto (non solo la programmazione, anche se
per noi è particolarmente sentito) sono le dipendenze:
ComponenteA usa ComponenteB, se cambi B molto probabilmente A si
scassa... e questo è male.
class ComponentA
{
void Foo()
{
ComponentB obj = new ComponentB();
obj.Execute();
}
}
class ComponentB
{
public void Execute()
{
//Do something...
}
}
Ma la domanda è A ha effettivamente bisogno di conoscere B? No, in
realtà gli basterebbe sapere che B è in grado di fare qualcosa non
tanto di conoscere B, possiamo quindi alzarci di un livello e dire che
A deve conoscere cosa fa B e non necessariamente B
ComponenteA conosce la "firma" (che descrive cosa fa B) di B e non
direttamente B
a questo punto l'unico legame è la *firma*, per il fx questo si traduce
in una interfaccia:
class ComponentA
{
void Foo()
{
*IComponentB* obj = new ComponentB();
obj.Execute();
}
}
interface IComponentB
{
void Execute();
}
class ComponentB : IComponentB
{
public void Execute()
{
//Do something...
}
}
come si vede ComponentA non deve necessariamente conoscere B ma gli
basterebbe conoscere la sola interfaccia, ma come fare per eliminare
quella fastidiosissima riga di codice:
IComponentB obj = new ComponentB();
in cui c'è ancora una dipendenza evidentissima?
Abbiamo bisogno di un terzo attore che sia in grado di risolvere la
dipendenza: Inverson of Control per l'appunto...
class ComponentA
{
void Foo()
{
IComponentB obj = ComponentProvider.Resolve<IComponentB>();
obj.Execute();
}
}
La parte che fa la magia è questa:
IComponentB obj = ComponentProvider.Resolve<IComponentB>();
il componente A in questo caso non sa più nulla del componente B,
figoso non trovi :-D
Il ComponentProvider è quello che fa la magia, data l'interfaccia che
vogliamo legge da un file di configurazione cosa ci deve ritornare e ci
ritorna l'istanza concreta di B, in questo caso, ma noi non lo
sappiamo... :-D
Come realizzare il ComponentProvider? non lo realizziamo ma ci
affidiamo a un framework che lo fa per noi, IMVHO il migliore in questo
momento è Spring.NET ma è decisamente complesso e la curva di
apprendimento iniziale abbastanza ripida, quindi per partire meglio
"Castle Windsor" che fa qualcosa meno ma è più immediato. Sul sito c'è
anche un breve tutorial che ti introduce ad IoC.
http://www.castleproject.org/container/index.html
http://www.castleproject.org/container/gettingstarted/part1/index.html
Mauro,Matteo
ritengo che la tua spiegazione sia stata molto chiara.
Penso di aver capito.
A questo punto vi chiedo per favore, di crearmi un mapping degli oggetti tra
quest'ultima spiegazione e gli oggetti della solution che mi ha proposto
Matteo in modo che possa capire meglio la solution pubblicata su UGI da
Matteo.
Inoltre: è possibile creare una semplice implementazione del
ComponentProvider senza andare a "tirare fuori" Spring.NET o Castle Windsor?
grazie tante ad entrambi!
ciao
mb
La solution comunque è pubblicata su CodePlex, non su UGI.
> Inoltre: è possibile creare una semplice implementazione del
> ComponentProvider senza andare a "tirare fuori" Spring.NET o Castle
> Windsor?
Sì, è esattamente quanto implementanto
attraverso la ValidationFactory, che restituisce
il provider concreto via Reflection, senza usare
toolkit aggiuntivi.
Nella spiegazione di Mauro, riferendomi alla mia solution:
- ComponentA: è la classe Person che necessità di un metodo per essere
validata
- ComponentB: ad esempio (ma è solo una delle possibilità) è la classe
HardCodedValidator
che viene delegata da ValidationFactory, tramite file di configurazione, ad
essere
la classe concreta che fornisce uno dei possibili metodi di validazione
Spero sia più chiaro.
> grazie tante ad entrambi!
1)Interface IValidableEntity
2)Interface IEntityValidator
3)FooValidator (Implements IEntityValidator)
4)Class ValidatorFactory
5)Class Person (Implements IValidableEntity)
Qualcosa mi sfugge, c'č un'oggeto in piů
nella spiegazione di Mauro ci sono 4 oggetti
1)A (person)
2)B (FooValidator)
3)ICombonentB (che č un'interfaccia-implementata da b)
4)IcomponentProvider
Qual'č l'oggetto in piů ....e perche? a cosa serve?
ciao grazie.
MB
Eh va beh, ma così non vale :-).
Stai confrontanto banane con mele :-)
- Person implementa IValidableEntity,
- I validatori concreti devono implementare IEntityValidator
- ValidationFactory è la factory che maschera il validatore concreto
Una domanda specifica? :-)
> ciao grazie.
You wrote :
> Qual'è l'oggetto in più ....e perche? a cosa serve?
>
smetti di cercare di capire la cosa in maniera così maccheronica, non
serve a nulla.
Guarda il tutorial di Castle che ti ho postato, vale anche se poi non
usi castle perchè ti spiega i concetti di base.
Inoltre fai un po' di prove, come ti fa fare il tutorial, in un
ambiente "protetto" che sia il più semplice possibile.