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 - [VB.NET] Classe comparer generica e sorting di collezioni generiche (ancora, XD)
Forum - C# / VB.NET - [VB.NET] Classe comparer generica e sorting di collezioni generiche (ancora, XD)

Pagine: [ 1 2 ] Precedente | Prossimo
Avatar
dedalux (Normal User)
Pro


Messaggi: 155
Iscritto: 14/02/2009

Segnala al moderatore
Postato alle 15:59
Mercoledì, 29/12/2010
Ebbene si, a volte sono testardo, e su questo problema mi ci sono puntato.
Voglio creare una classe AutoSortableObservableCollection(Of T), e ho pensato di ereditare dall'observable semplice, aggiungengo una procedura Sort() che ordinando una List(Of T) creata dalla collezione.ToList(), ricavi gli indici degli elementi ordinati in quest'ultima utilizzando il Comparer Generico, e riordini la collezione.

Il codice penso sia più chiaro

Tutto nello stesso Namespace

Questa è la Collezione

Codice sorgente - presumibilmente VB.NET

  1. ''' <summary>
  2.     ''' Enumerazione delle direzioni di ordinamento.
  3.     ''' </summary>
  4.     ''' <remarks></remarks>
  5.     Public Enum OrderDirection As Short
  6.         Ascending = -1
  7.         Descending = 1
  8.     End Enum
  9.  
  10.     Public Class AutoSortableObservableCollection(Of T)
  11.         Inherits ObservableCollection(Of T)
  12.  
  13.  
  14.         ''' <summary>
  15.         ''' Inizializza una nuova istanza di AutoSortableObservableCollection(Of T).
  16.         ''' </summary>
  17.         ''' <param name="SortingPropertyName">Nome della proprietà in base alla quale ordinare la collezione.</param>
  18.         ''' <param name="IsAutoSortActive">Indica se abilitare l'ordinamento automatico (predefinito: si).</param>
  19.         ''' <param name="SortingDirection">Direzione dell'ordinamento (predefinito: dall'altro verso il basso).</param>
  20.         ''' <remarks></remarks>
  21.         Sub New(ByVal PropertyName As String,
  22.                 Optional ByVal IsAutoSortActive As Boolean = True,
  23.                 Optional ByVal Order As OrderDirection = OrderDirection.Ascending)
  24.             SortingPropertyName = PropertyName
  25.             AutoSort = IsAutoSortActive
  26.             OrderDirection = Order
  27.         End Sub
  28.  
  29. #Region "Proprietà"
  30.  
  31.         ''' <summary>
  32.         ''' Nome della proprietà in base alla quale ordinare la collezione.
  33.         ''' </summary>
  34.         ''' <remarks></remarks>
  35.         Dim _SortingPropertyName As String
  36.         Public Property SortingPropertyName As String
  37.             Get
  38.                 Return _SortingPropertyName
  39.             End Get
  40.             Set(ByVal value As String)
  41.                 If value <> _SortingPropertyName Then
  42.                     _SortingPropertyName = value
  43.                     If _AutoSort Then Sort(_SortingPropertyName, OrderDirection)
  44.                 End If
  45.             End Set
  46.         End Property
  47.  
  48.         ''' <summary>
  49.         ''' Indica se l'ordinamento automatico è abilitato.
  50.         ''' </summary>
  51.         ''' <remarks></remarks>
  52.         Dim _AutoSort As Boolean
  53.         Public Property AutoSort As Boolean
  54.             Get
  55.                 Return _AutoSort
  56.             End Get
  57.             Set(ByVal value As Boolean)
  58.                 If value <> _AutoSort Then
  59.                     _AutoSort = value
  60.                     If _AutoSort Then Sort()
  61.                 End If
  62.             End Set
  63.         End Property
  64.  
  65.         ''' <summary>
  66.         ''' Direzione dell'ordinamento.
  67.         ''' </summary>
  68.         ''' <remarks></remarks>
  69.         Dim _OrderDirection As OrderDirection
  70.         Public Property OrderDirection As OrderDirection
  71.             Get
  72.                 Return _OrderDirection
  73.             End Get
  74.             Set(ByVal value As OrderDirection)
  75.                 If value <> _OrderDirection Then
  76.                     _OrderDirection = value
  77.                     If _AutoSort Then Sort(_SortingPropertyName, OrderDirection)
  78.                 End If
  79.             End Set
  80.         End Property
  81.  
  82. #End Region
  83.  
  84. #Region "Metodi"
  85.  
  86.         ''' <summary>
  87.         ''' Ordina la collezione utilizzando i parametri dettati dalle proprietà legate all'ordinamento.
  88.         ''' </summary>
  89.         ''' <remarks></remarks>
  90.         Sub Sort()
  91.             Dim me2 As List(Of T) = Me.ToList
  92.             me2.Sort(New GenericComparer(Of T)(_SortingPropertyName, _OrderDirection))
  93.             For Each obj As T In me2
  94.                 Me.Move(Me.IndexOf(obj), me2.IndexOf(obj))
  95.             Next
  96.             me2.Clear()
  97.             me2 = Nothing
  98.         End Sub
  99.  
  100.         ''' <summary>
  101.         ''' Imposta le proprietà legate all'ordinamento su quelle passate come parametri,
  102.         ''' e chiama il metodo Sort().
  103.         ''' </summary>
  104.         ''' <param name="PropName">Nome della proprietà in base alla quale ordinare la collezione.</param>
  105.         ''' <param name="Direction">Direzione dell'ordinamento della collezione.</param>
  106.         ''' <param name="DeactivateAutoSortAfterSorting">Indica se dopo l'ordinamento l'AutoSorting dev'essere disattivato.</param>
  107.         ''' <remarks></remarks>
  108.         Sub Sort(ByVal PropName As String, ByVal Direction As OrderDirection, Optional ByVal DeactivateAutoSortAfterSorting As Boolean = False)
  109.             SortingPropertyName = PropName
  110.             OrderDirection = Direction
  111.  
  112.             Sort()
  113.  
  114.             If DeactivateAutoSortAfterSorting Then AutoSort = False
  115.  
  116.         End Sub
  117.  
  118.         ''' <summary>
  119.         ''' Inverte lo stato dell'ordinamento automatico.
  120.         ''' </summary>
  121.         ''' <remarks></remarks>
  122.         Sub ToggleAutoSort()
  123.             AutoSort = Not _AutoSort
  124.         End Sub
  125.  
  126.         ''' <summary>
  127.         ''' Inverte la direzione dell'ordinamento.
  128.         ''' </summary>
  129.         ''' <remarks></remarks>
  130.         Sub ToggleOrder()
  131.             _OrderDirection *= -1
  132.         End Sub
  133.  
  134. #End Region
  135.  
  136.         Protected Overrides Sub OnCollectionChanged(ByVal e As System.Collections.Specialized.NotifyCollectionChangedEventArgs)
  137.             MyBase.OnCollectionChanged(e)
  138.             Try
  139.                 If _AutoSort Then Sort()
  140.             Catch ex As Exception
  141.                 MessageBox.Show(ex.Message)
  142.             End Try
  143.         End Sub
  144.  
  145.     End Class



Questo è il Comparer

Codice sorgente - presumibilmente VB.NET

  1. Public Class GenericComparer(Of T)
  2.         Implements IComparer(Of T)
  3.  
  4.         Protected Friend SortPropName As String
  5.         Protected Friend SortOrder As OrderDirection
  6.  
  7.         ''' <summary>
  8.         ''' Inizializza una nuova istanza di GenericComparer(Of T)
  9.         ''' </summary>
  10.         ''' <param name="PropertyName">Proprietà </param>
  11.         ''' <param name="Direction"></param>
  12.         ''' <remarks></remarks>
  13.         Sub New(ByVal PropertyName As String,
  14.                Optional ByVal Direction As OrderDirection = OrderDirection.Ascending)
  15.             SortPropName = PropertyName
  16.             SortOrder = Direction
  17.         End Sub
  18.  
  19.         ''' <summary>
  20.         ''' Restituisce il risultato del confronto tra due oggetti.
  21.         ''' </summary>
  22.         ''' <param name="x">Primo oggetto del confronto.</param>
  23.         ''' <param name="y">Secondo oggetto del confronto.</param>
  24.         ''' <returns></returns>
  25.         ''' <remarks></remarks>
  26.         Public Function Compare(ByVal x As T, ByVal y As T) As Integer _
  27.             Implements System.Collections.Generic.IComparer(Of T).Compare
  28.  
  29.             If SortPropName <> String.Empty Then
  30.  
  31.                 Dim pi As PropertyInfo = GetType(T).GetProperty(SortPropName)
  32.                 Dim xObj As IComparable = DirectCast(pi.GetValue(x, Nothing), IComparable)
  33.                 Dim yObj As IComparable = DirectCast(pi.GetValue(y, Nothing), IComparable)
  34.  
  35.                 If SortOrder = OrderDirection.Ascending Then
  36.                     Return xObj.CompareTo(yObj)
  37.                 Else
  38.                     Return -xObj.CompareTo(yObj)
  39.                 End If
  40.  
  41.             End If
  42.  
  43.             Return 0
  44.  
  45.         End Function
  46.  
  47.     End Class



A parte che il codice

Codice sorgente - presumibilmente VB.NET

  1. Private Sub AutoSortableObservableCollection_CollectionChanged(ByVal sender As Object,
  2.                                                                        ByVal e As System.Collections.Specialized.NotifyCollectionChangedEventArgs) _
  3.                                                                    Handles Me.CollectionChanged
  4.             Try
  5.                 If _AutoSort Then Sort()
  6.             Catch ex As Exception
  7.                 MessageBox.Show(ex.Message)
  8.             End Try
  9.         End Sub



non funziona, e mi tocca fare .Sort dall'esterno,
il problema è che quando chiamo la prima volta la procedura Sort, mi mostra gli elementi in un determinato ordine, quando poi faccio un'aggiunta (con .Add) e richiamo Sort, mi distribuisce gli elementi in un'altro ordine, che non poi non cambia negli ordinamenti successivi. Salvo la collezione su file, la ricarico, l'ordine è quello del primo Sort.

Perfavore, aiutatemi a capire :d:d

P.S. se volete un piccolo progetto di esempio ve lo prepare e lo allego, ma ho assolutamente bisogno di comprendere il problema

GRAZIE

Ultima modifica effettuata da dedalux il 29/12/2010 alle 16:25
PM
Avatar
HeDo (Founder Member)
Guru^2


Messaggi: 2765
Iscritto: 21/09/2007

Up
1
Down
V
Segnala al moderatore
Postato alle 16:40
Mercoledì, 29/12/2010

quello che continua a sfuggirti è che NON puoi fare il sorting di una collection generica all'infuori di un sort generale basato sul comparer di default in quanto NON sai il tipo degli elementi che ci sono dentro NE' su cosa ordinare.

L'unico modo per fare quello che vuoi fare è imporre al tipo degli elementi della collection di ereditare da una classe/interfaccia che esponga qualcosa come un campo o un comparer su cui basare il sort.

il resto credo siano vaneggiamenti :)

PM
Avatar
Gianluca87 (Ex-Member)
Expert


Messaggi: 300
Iscritto: 16/11/2008

Up
1
Down
V
Segnala al moderatore
Postato alle 23:07
Domenica, 02/01/2011
non so ci andrei comunque cauto... dipende dall'ordine di grandezza che consideri.... comunque sono discorsi abbastanza filosofici... al dilà di questo è notevole leggere su questo forum dei concetti di questa levatura... come prossimo passaggio ti consiglio di passare a un linguaggio un pò meno fumoso o fuffoso magari c#

PM
Avatar
dedalux (Normal User)
Pro


Messaggi: 155
Iscritto: 14/02/2009

Up
0
Down
V
Segnala al moderatore
Postato alle 17:21
Mercoledì, 29/12/2010
Grazie HeDo per la risposta.
Sarà la mancanza di sonno delle vacanze, ma non ho capito cosa intendi con "all'infuori"..
Da quello che hai scritto capisco che la soluzione che proponi sarebbe far implementare IComparable (http://msdn.microsoft.com/it-it/library/ey2t2ys5.aspx) a qualsiasi classe io voglia usare al posto di T, per poter esporre il metodo CompareTo
ma il problema è che il metodo CompareTo può basarsi solo su una proprietà, come faccio se la proprietà la deve scegliere l'utente...? ç_ç
Senza contare che fare questo lavoro per ogni classe non è certo poco lavoro...

Secondo me una soluzione c'è!
Se l'hai capita, non è che potresti graziarmi? 8-|

Ultima modifica effettuata da dedalux il 29/12/2010 alle 17:26
PM
Avatar
Gianluca87 (Ex-Member)
Expert


Messaggi: 300
Iscritto: 16/11/2008

Up
0
Down
V
Segnala al moderatore
Postato alle 17:32
Mercoledì, 29/12/2010
Ciao, secondo ti sfugge il problema di fondo... se la lista contiene N elementi T Generici...con quale criterio li ordini, se assumi il fatto che siano stringhe o numeri è inutile che usi l'oggetto T comunque... per ordinare le liste.. LinqToObject, nessun ciclo 1 riga di codice .OrderBy(X=>X.Property).ToList(),
se invece il tuo oggetto può contenere un T primitivo puoi prevedere degli ordinamenti di default in base al tuo T primitivo.

PM
Avatar
dedalux (Normal User)
Pro


Messaggi: 155
Iscritto: 14/02/2009

Up
0
Down
V
Segnala al moderatore
Postato alle 18:06
Mercoledì, 29/12/2010
Gianluca, non vedo in che modo possa influire la quantità N di elementi da ordinare, se non in termini di tempo.
Comunque la collezione (che non è una lista) contiene elementi T che NON sono tipi primitivi, ma classi, e l'ordinamento di queste deve avvenire in base ad una proprietà scelta a runtime (tra quelle della classe).

Quello che mi proponi te se ho ben capito, è un'espressione Lamba, che in VB.NET, nel mio caso, sarebbe da tradurre così

Codice sorgente - presumibilmente C# / VB.NET

  1. Dim me2 = Me.ToList.OrderBy(Function(f As T) f.Proprietà)'.ThenBy ...



e poi fare anche qui una cosa di questo genere

Codice sorgente - presumibilmente VB.NET

  1. me2.Sort(New Comparison(Of T) _
  2.                      (Function(t1 As T, t2 As T) TipoDellaProprietà.Compare(t1.Proprietà, t2.Proproetà)))
  3.  
  4.             For Each tObj As TIn me2
  5.                 Me.Move(Me.IndexOf(tObj), me2.IndexOf(tObj))
  6.             Next



ed il risultato non è diverso

Ultima modifica effettuata da dedalux il 29/12/2010 alle 18:07
PM
Avatar
HeDo (Founder Member)
Guru^2


Messaggi: 2765
Iscritto: 21/09/2007

Up
0
Down
V
Segnala al moderatore
Postato alle 18:44
Mercoledì, 29/12/2010
Testo quotato

Postato originariamente da dedalux:

Grazie HeDo per la risposta.
Sarà la mancanza di sonno delle vacanze, ma non ho capito cosa intendi con "all'infuori"..
Da quello che hai scritto capisco che la soluzione che proponi sarebbe far implementare IComparable (http://msdn.microsoft.com/it-it/library/ey2t2ys5.aspx) a qualsiasi classe io voglia usare al posto di T, per poter esporre il metodo CompareTo
ma il problema è che il metodo CompareTo può basarsi solo su una proprietà, come faccio se la proprietà la deve scegliere l'utente...? ç_ç
Senza contare che fare questo lavoro per ogni classe non è certo poco lavoro...

Secondo me una soluzione c'è!
Se l'hai capita, non è che potresti graziarmi? 8-|



la proprietà scelta dall'utente viene infatti specificata all'interno dell'implementazione personalizzata di CompareTo :)
infatti al suo interno la classe provvederà a stabilire il rapporto d'ordine con un'altra classe, in base ad un criterio personalizzato.

PM
Avatar
dedalux (Normal User)
Pro


Messaggi: 155
Iscritto: 14/02/2009

Up
0
Down
V
Segnala al moderatore
Postato alle 19:07
Mercoledì, 29/12/2010
Mi dai l'idea di avere in mente la soluzione, siccome così non la capisco molto 8-| non è che potresti entrare in chat che ne parliamo un'attimino?

Grazie HeDo :)

PM
Avatar
HeDo (Founder Member)
Guru^2


Messaggi: 2765
Iscritto: 21/09/2007

Up
0
Down
V
Segnala al moderatore
Postato alle 20:54
Mercoledì, 29/12/2010
Testo quotato

Postato originariamente da dedalux:

Mi dai l'idea di avere in mente la soluzione, siccome così non la capisco molto 8-| non è che potresti entrare in chat che ne parliamo un'attimino?

Grazie HeDo :)



così su due piedi:

Codice sorgente - presumibilmente C#

  1. class AutoSortableObservableCollection<T> : ObservableCollection<T>
  2.     {
  3.  
  4.         public Comparison<T> Comparer { get; set; }
  5.  
  6.         public void Sort()
  7.         {
  8.  
  9.             T[] temp = this.Items.ToArray<T>();
  10.  
  11.             Array.Sort<T>(temp, Comparer);
  12.  
  13.             this.Items.Clear();
  14.  
  15.             foreach (var item in temp)
  16.                 this.Items.Add(item);
  17.  
  18.         }
  19.     }



Comparer è un campo pubblico che rappresenta il comparatore degli elementi, può essere specificato a runtime e modifica dinamicamente l'ordinamento degli elementi.


PM
Pagine: [ 1 2 ] Precedente | Prossimo