Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
C# / VB.NET - Organizzazioni in Classi - 2
Forum - C# / VB.NET - Organizzazioni in Classi - 2

Pagine: [ 1 2 3 ] Precedente | Prossimo
Avatar
Renny (Normal User)
Expert


Messaggi: 231
Iscritto: 30/07/2011

Segnala al moderatore
Postato alle 15:17
Martedì, 09/08/2011
Ciao a tutti.:)
Ricollegandomi a questo http://www.pierotofy.it/pages/extras/forum/16/1029500-[vbn ...
Vorrei postare un po' di codice, così magari mi potete dare qualche suggerimento per ottimizzare il tutto.. Mi rendo conto che su questo forum ci sono discussioni di livello ben più elevato della mia ma magari a qualche utente alle prime armi possono interessare anche argomenti di base..
Sto realizzando un parser per delle stringhe codificate in un certo modo.
Avevo pensato di organizzarla così:
http://img8.imageshack.us/img8/4269/esempioschema.jpg
Sull'evento KeyUp di una textbox rilevo il testo inserito:
Codice sorgente - presumibilmente VB.NET

  1. If e.KeyCode = Keys.Enter Then 'evento tasto INVIO
  2.             e.SuppressKeyPress = True
  3.             Dim R As New Stringa 'Istanzio una nuova STRINGA
  4.             R.AnalizzaStringa(textbox1.Text) 'Richiamo il Metodo ANALIZZASTRINGA


La Classe stringa riceve il testo e tramite delle espressioni regolari che ho scritto separa la stringa nei suoi vari elementi
Codice sorgente - presumibilmente VB.NET

  1. Public Class Stringa
  2.     Public Sub AnalizzaStringa(ByVal str As String)
  3.         If str.Length = 0 Then Exit Sub
  4.         Dim MatchCollect As MatchCollection
  5.         Dim t As Match
  6.         Dim strRegex As String = "ecc ecc"


Se l'espressione regolare restituisce match adeguato istanzio un nuovo oggetto Elemento1, che conterrà un singolo elemento della stringa inserita
Codice sorgente - presumibilmente C# / VB.NET

  1. Dim Elem1 As New Elemento1(t.Groups("Elem1").Value)


Ho quindi creato la Classe Elemento1 dove ho messo dei metodi per verificare la correttezza dell'elemento1
Codice sorgente - presumibilmente VB.NET

  1. Public Class Elemento1
  2.     Inherits FormattaStr 'classe con funzione x formattare la stringa
  3.     Private Elem1Array As New List(Of String)(New String() {"A", "AB", "B", "BS", "BT", "Abs"}) 'array contenente tutti i possibili valori di elem1
  4.     Dim _Elem As String
  5.     Dim E As New ErrorWr
  6.  
  7.     Public Sub New(ByVal str As String)
  8.         _Elem = str
  9.         _Elem = FormToUpperInv(_Elem) '1 carattere Maiuscolo e resto minuscolo
  10.         If Not Elem1Array.Contains(_Elem) Then 'se l'elemento è sbagliato
  11.             E.WriteError("Elemento1", _Elem) '-> classe per segnalare l'errore
  12.         End If
  13.     End Sub
  14.  
  15.     Public Function str() As String
  16.         Return _Elem
  17.     End Function
  18. End Class


Lo stesso discorso vale per gli altri elementi, anche se trattandosi di pezzetti di stringa più lunghi ci sono altre regole per valutare la correttezza di quanto inserito.
Le mie domande sono:
1) si può migliorare qualcosa, nelle dichiarazioni/creazioni delle classi ?
2) la classe ErrorWr espone un metodo che non fa altro che ricevere 2 "stringhe" contenenti l'errore per visualizzarlo con messagebox.show... Un eventuale comando "exit sub" per bloccare l'elaborazione dove va messo?
3) Se volessi definire degli errori "standard" tipo "elemento inesistente", "elemento doppio", "con elemento y non è possibile inserire elemento x", come mi consigliate di procedere?
Grazie a tutti per l'attenzione:asd:
Mi rendo conto che usare VB.NET per un programma del genere è come usare un cannone per ammazzare le mosche, ma se non altro sto imparando qualcosa di molto utile e interessante.. :k:


Renny ha allegato un file: Esempio Schema.JPG (21359 bytes)
Clicca qui per guardare l'immagine

Ultima modifica effettuata da Renny il 09/08/2011 alle 20:48
PM Quote
Avatar
Il Totem (Admin)
Guru^2


Messaggi: 3635
Iscritto: 24/01/2006

Segnala al moderatore
Postato alle 11:40
Mercoledì, 10/08/2011
La classe Stringa può andare, ma potrebbe essere migliorata. La mia opinione è di non esporre un costruttore pubblico. Infatti tu puoi creare una nuova Stringa, come hai fatto nel codice di esempi, che può non contiene nulla. Perciò è sempre possibile creare un oggetto incoerente. Dovresti invece convertire AnalizzaStringa in un metodo factory:
http://totemslair.org/guide/viewchapter.php?guida=vb&id=25

La classe Elemento1 è molto... sgraziata. Per prima cosa, Elemento1 eredita da una classe base che non espone funzionalità relative all'elemento ma alle stringhe e, pur essendo Elemento1 stesso una qualche forma derivata di stringa, non ha nulla a che vedere con le stringhe in generale. Dovresti spostare tutti i metodi di FormattaStr o in un modulo accessibile da tutti (proprio come Math espone funzioni di calcolo) oppure, ancora meglio, convertire tutti questi metodi in metodi di estensione per la classe String:
http://totemslair.org/appunti/viewtutorial.php?id=8
Ora, tolto il grado di derivazione da FormattaStr, puoi concentrarti sull'elemento. Pare strano... molto strano, che esistano più classi chiamate Elemento1, Elemento2, ecc... Se questo è necessario io non lo so, poiché dipende da come devi parsare la stringa. Tuttavia sono abbastanza sicuro che dovresti accomunare queste classi facendole derivare tutte dalla stessa classe base (magari astratta) Elemento.
http://totemslair.org/guide/viewchapter.php?guida=vb&id=36

Infine, gli errori non dovrebbero essere semplicemente trascritti da qualche parte. Dovresti invece lanciare delle eccezioni con Throw. In questo modo è molto più semplice definire i tipi di errore: basta creare delle classi che ereditino da Exception e poi usare Throw per lanciarne delle istanze. Ad esempio:
Codice sorgente - presumibilmente VB.NET

  1. Class InvalidElementException
  2.    Inherits Exception
  3.  
  4.    Public Sub New(ByVal message As String)
  5.       MyBase.Message = message
  6.    End Sub
  7. End Class
  8.  
  9. '...
  10.  
  11. If Not Elem1Array.Contains(_Elem) Then 'se l'elemento è sbagliato
  12.    Throw New InvalidElementException("Elemento1")
  13. End If
  14.  
  15. ' E, fuori
  16.  
  17. Try
  18.    R.AnalizzaStringa(textbox1.Text)
  19. Catch ieEx As InvalidElementException
  20.    MessageBox.Show(ieEx.Message)
  21. End Try


PM Quote
Avatar
Renny (Normal User)
Expert


Messaggi: 231
Iscritto: 30/07/2011

Segnala al moderatore
Postato alle 15:22
Mercoledì, 10/08/2011
Ciao Totem, grazie mille per la risposta e per i tuoi preziosi consigli. :hail:
1) questione: Metodo Factory
Ho pensato di creare un metodo Factory sia per creare (e verificare) la stringa sia nel momento in cui creo i singoli elementi.
Ho fatto quindi
Codice sorgente - presumibilmente VB.NET

  1. Public Class Elemento1
  2.  
  3.     Private ReadOnly _Elem As String 'campo interno readonly
  4.     Public ReadOnly Property Elem 'restituisce il valore di elem
  5.         Get
  6.             Return _Elem
  7.         End Get
  8.     End Property
  9. 'in ingresso ho la substring che contiene il valore elem inserito dall'utente
  10.     Public Shared Function Create(ByVal str As String)
  11.        'array di verifica con i valori accettati di Elem
  12.         Dim ElemArray As New List(Of String)(New String() {"A", "Ab", "B", "Bs"}
  13.         'formatto str
  14.         If String.IsNullOrEmpty(str) Then
  15.             'raise expetion -> scrivere classe per gestione eccezioni
  16.         Else
  17.             If str.LastS Then 'metodo extentions verifica se ultimo char è una S
  18.                 str = str.FormatUpDowdUp 'formatto Maiuscolo minuscolo Maiuscol
  19.             Else
  20.                 str = str.FormatUpDownDown 'formatto Maiuscolo minuscolo
  21.             End If
  22.             If LocArray.Contains(str) Then 'verifico l'elemento
  23.                 Return New Elemento1(str)
  24.             Else
  25.                 'errore -> errore in elemento1, str inesistente
  26.                 return nothing '??? è corretto fare così?
  27.             End If
  28.         End If
  29.        
  30.     End Function
  31.     'costruttore di elemento1
  32.     Private Sub New(ByVal Elem As String)
  33.         _Elem = Elem
  34.     End Sub
  35. End Class


A livello invece della stringa (l'insieme degli elementi) ho fatto così:
Codice sorgente - presumibilmente VB.NET

  1. Public Class Stringa
  2.      'variabili interne
  3.     Private ReadOnly _Elem1 As Elemento1
  4.     Private ReadOnly _Elem2 As Elemento2
  5.  
  6.     Public ReadOnly Property Elem1Value As Elemento1
  7.         Get
  8.             Return _Elem1
  9.         End Get
  10.     End Property
  11.    'stessa property anche per Elem2
  12.  
  13.     'riceve la stringa di input inserita dell'utente nella textbox
  14.     Public Shared Function Create(ByVal str As String) As Stringa
  15.         Dim Elem1 As Elemento1
  16.         Dim Elem2 As Elemento2
  17.  
  18.         If String.IsNullOrEmpty(str) Then Return Nothing 'verifico str nulla
  19.  
  20.         If Not str.Contains(" ") Then Return Nothing 'deve contenere " "
  21.          
  22.          Dim mt As Match
  23.         'leggo Elem1 - Elem2
  24.         mt = Regex.Match(str, regexstr)
  25.         If mt.Success Then
  26.             Elem1 = Elemento1.Create(mt.Groups("Elem1").Value)
  27.             Elem2 = Elemento2.Create(mt.Groups("Elem2").Value)
  28.        ...........
  29.      'inserisco tutti gli elementi e faccio le verifiche adeguate
  30.       Return New Stringa(Elem1, Elem2.... )
  31.      end function
  32.      ........
  33.     Private Sub New(ByRef Elem1 As Elemento1, ByVal Elem2 As Elemento2)
  34.         _Elem1 = Elem2 '
  35.         _Elem2 = Elem2
  36.     End Sub
  37. end Class


Come vedi ho usato le Extension per crearmi quei metodi aggiuntivi alla classe string che mi servivano per formattare la stringa come volevo io.. (davvero interessanti!)
Rispetto alle classi astratte, ho letto l'interessante esempio che mi hai linkato ma preferisco lasciare l'organizzazione così. Anche perché qua scrivo "Elem1" ecc ma nel mio programma gli elementi hanno nomi diversi e contengono dati diversi (sempre caratteri alfanumerici) ma sono ben distinti.
Concettualmente mi sembra di aver capito abbastanza come funziona il tutto.
L'unica cosa è che mi sembra di dover scrivere tanto codice, perchè gli elementi di stringa sono 7.. Non è che così facendo si occupa molta memoria, a dover dichiarare le variabili tante volte? Se la stringa (o il singolo elemento) non sono corretti, ha senso scrivere "return nothing" e comunque avendo l'exception esco dalla function "Create" ed evidenzio all'utente l'errore?
Per quanto riguarda la gestione degli errori, finisco con la Classe string e poi mi ci metto. Al limite se ho dubbi scrivo ancora..
Di nuovo Grazie mille!:k:

Ultima modifica effettuata da Renny il 10/08/2011 alle 15:29
PM Quote
Avatar
Il Totem (Admin)
Guru^2


Messaggi: 3635
Iscritto: 24/01/2006

Segnala al moderatore
Postato alle 11:47
Giovedì, 11/08/2011
"Tanta" memoria dipende dal contesto. E' difficile occupare tanta memoria usando solo stringhe, a meno che, ovviamente, non lasci in giro dei memory leak assurdi.
Appunto perché ti sembra di dover scrivere cose ripetute è opportuno avere una classe base Elemento, che esponga le funzionalità comuni a tutti gli elementi.

Per quanto riguarda Return Nothing, sebbene sia una pratica abbastanza comune restituire oggetti nulli, non si tratta della soluzione migliore. Usa invece un'eccezione, esattamente come hai fatto per str.IsNullOrEmpty.
Altri appunti:
- Dopo Throw, il flusso di esecuzione viene deviato al di fuori del metodo e, se esiste un blocco Catch opportuno, all'interno di quest'ultimo. Perciò, in questo codice, l'else è inutile:
Codice sorgente - presumibilmente VB.NET

  1. If String.IsNullOrEmpty(str) Then
  2.    Throw New QualcheEccezione()
  3. Else
  4.    '...
  5. End If


- Cerca di usare eccezioni standard dove possibile. Ad esempio, nel caso di stringa vuota, potresti lanciare un'eccezione di tipo ArgumentException, che indica che un argomento del metodo non è valido. In questo caso è l'unica stringa passata a non essere valida, dato che è vuota.
- Usa metodi di estensione con dei nomi comprensibili. E non ripeterti. Ad esempio, LastS è inutile, dato che esiste il metodo String.EndsWith(str), il quale restituisce vero se la stringa su cui è richiamato termina con str. str.LastS è simile a str.EndsWith("S").

LocArray da dove viene? Non è molto elegante usare una variabile globale nel corpo di una classe.

PM Quote
Avatar
Renny (Normal User)
Expert


Messaggi: 231
Iscritto: 30/07/2011

Segnala al moderatore
Postato alle 17:08
Giovedì, 11/08/2011
Ciao Totem, ciao ragazzi...
Sto ancora lavorando per creare le mie classi usando metodi Factory, per verificare i dati e solo se è tutto ok, posso instanziare l'oggetto.
Il mio dubbio è questo:
Codice sorgente - presumibilmente VB.NET

  1. Shared Function Create(ByVal str As String) As Elem1
  2.         Dim ElemArray As New List(Of String)(New String() {"elementi vari"                                            
  3.         Dim ElemList As New List(Of String)(str.Split(".")) 'divido la stringa
  4.         Dim DetsStr As String = Nothing
  5.         str = formatta(str) '->> richiamo una funzione all'interno della classe Elem1
  6.         return new Elem1(str)
  7. end Function
  8.  
  9. Private Function formatta(str as string) as string
  10. str = str.toLower ' solo per fare l'esempio
  11. return str
  12. end Function


Il mio dubbio è il seguente: non posso richiamare la funzione "formatta" all'interno del metodo factory perché è definito shared. L'errore che mi riporta Visual Studio è appunto "Impossibile fare riferimento a un membro di istanza di una classe all'interno di un metodo condiviso o di un inizializzatore di membri condivisi senza un'istanza esplicita della classe."
Come posso fare per richiamare la mia funzione all'interno del metodo Create?
Devo per forza metterla in una classe astratta e poi far ereditare tale classe base alla classe Elem1, dove c'è il create? (Ho provato un po,senza successo).. Questa cosa non è che mi piaccia tanto, perché la funzione che sto cercando di usare mi serve solo all'interno di elem1.. La cosa più semplice è spostare il codice nel metodo create, ma mi pare impossibile che non ci siano altre soluzioni. Che dite?8-|




PM Quote
Avatar
Phil93 (Normal User)
Pro


Messaggi: 85
Iscritto: 26/01/2011

Segnala al moderatore
Postato alle 3:08
Venerdì, 12/08/2011
Ci mancherebbe altro che VS ti dia errore. E' impossibile fare riferimento a qualunque membro d'istanza da un metdo statico. Il motivo è talmente ovvio che non mi dilungo neanche a spiegarlo. A ogni modo, non ti basta rendere la funzione Formatta anche essa statica? Non vedo dove sia il problema.

Spero di aver capito bene ciò che intendi fare.

Ultima modifica effettuata da Phil93 il 12/08/2011 alle 3:10
PM Quote
Avatar
Il Totem (Admin)
Guru^2


Messaggi: 3635
Iscritto: 24/01/2006

Segnala al moderatore
Postato alle 11:54
Venerdì, 12/08/2011
Appunto, è un tuo errore. Formatta dovrebbe essere un metodo di estensione di String. Non ha senso dichiararlo come metodo d'istanza, poiché non fa uso di nessun campo d'istanza. Al più potrebbe essere statico, come suggeriva Phil93.

PM Quote
Avatar
Renny (Normal User)
Expert


Messaggi: 231
Iscritto: 30/07/2011

Segnala al moderatore
Postato alle 12:31
Sabato, 13/08/2011
Ciao ragazzi, grazie per la risposta.
In realtà la mia intenzione con il codice che avevo scritto era molto banale (e forse anche un po' stupida). Semplicemente volevo che il codice della funzione "formatta" fosse a parte, ma solo per tirarlo fuori e metterlo come funzione poco più un là, nella classe che lo utilizza. tipo
Codice sorgente - presumibilmente VB.NET

  1. Public Class Elemento1
  2. Shared Function Create(ByVal str As String) As Elemento1
  3. str = formatta(str)
  4. '... altre istruzioni di controllo su str
  5. '... con relativi Throw New QualcheEccezione()
  6. return New Elemento1(str)


In questo modo la funzione Formatta serve solo a evitare di appesantire il codice "di controllo" che genera l'elemento. Ma in effetti è una funzione con qualche if, che posso utilizzare solo in questa classe perché troppo specifica. Non ha senso come extention, (forse neanche tanto come "funzione), ma alla fine l'ho dichiarata così:
Codice sorgente - presumibilmente VB.NET

  1. Shared Private Function Formatta(str as string)as string
  2. 'formattazioni varie.


Ne è uscito quasi un'ossimoro: una funzione condivisa ma privata, solo per la classe...8-| Così fa il suo lavoro, anche se è sicuramente un modo stupido di procedere.. che dite?
Resta il fatto che con il vostro aiuto sono andato a rileggermi con attenzione questa OTTIMA guida: :k:
http://totemslair.org/guide/viewchapter.php?guida=vb&id=23
Di nuovo grazie :hail:

PM Quote
Avatar
Phil93 (Normal User)
Pro


Messaggi: 85
Iscritto: 26/01/2011

Segnala al moderatore
Postato alle 22:50
Sabato, 13/08/2011
Che sia utile spezzare o meno il codice poi lo decidi te, c'è chi si tiene funzioni lunghe 100 righe e chi le spezza a seconda del "compitino". :k:

PM Quote
Pagine: [ 1 2 3 ] Precedente | Prossimo