none
Avviso: L'interfaccia 'IComparer(Of X)' presenta ambiguità rispetto a un'altra interfaccia implementata 'IComparer(Of Y)' RRS feed

  • Domanda

  • Buon anno a tutti!!!

    Che warning è? Che vuol dire?

    Volevo utilizzare un oggetto per ordinare un Generic.List(Of X) dove X può essere di due tipi differenti e l'iComparer si deve comportare in maniera differente, ma non volevo andare ad analizzare il tipo degli oggetti della lista (che sono tutti dello stesso tipo perché Generic), per cui utilizzavo un oggetto che fa da comparer per entrambi i tipi:

        Private Class _CmbItemComparer
            Implements IComparer(Of CmbItem(Of String, Integer))
            Implements IComparer(Of CmbItem(Of Integer, Integer))
    
            Public Function Compare(x As CmbItem(Of String, Integer), y As CmbItem(Of String, Integer)) As Integer Implements IComparer(Of CmbItem(Of String, Integer)).Compare
                Return x.Value.CompareTo(y.Value)
            End Function
    
            Public Function Compare1(x As CmbItem(Of Integer, Integer), y As CmbItem(Of Integer, Integer)) As Integer Implements IComparer(Of CmbItem(Of Integer, Integer)).Compare
                Return x.Value.CompareTo(y.Value)
            End Function
        End Class
    

    Nella finestra Elenco errori mi appare il Warning in oggetto. In realtà sembra che funzioni comunque bene, ma mi piacerebbe sapere il perché del warning.

    Grazie

    giovedì 2 gennaio 2014 14:51

Risposte

  • Perchè la comparazione di due oggetti dello stesso tipo presenti nella stessa raccolta basandosi su due input di comparazione diversi è ambigua. Come esplicitato in msdn che ti consiglia di derivare dalla classe Comparer(of T) piuttosto che implementarne l'interfaccia di base. 

    È consigliabile derivare dalla classe Comparer(Of T) anziché implementare l'interfaccia IComparer(T) perché la classe Comparer(Of T) fornisce un'implementazione esplicita dell'interfaccia del metodo IComparer.Compare e della proprietà Default che ottiene l'operatore di confronto predefinito per l'oggetto.

    In altre parole, il metodo Compare vuole avere un'unica implementazione di comparazione per capire se un oggetto è maggiore di un altro, altrimenti rischia di essere una comparazione ambigua. Ti faccio un esempio:

    Oggetto 1

    ID: 1

    Nome: Zanzara

    Oggetto 2

    ID: 2

    Nome: Ape

    Se inseriti all'interno della stessa collection, quale dei due è maggiore? Se analizzi l'ID è maggiore il secondo, se analizzi il nome è maggiore il primo. Ecco da dove nasce l'ambiguità per il compilatore.

    HTH


    Alberto De Luca [MVP - Visual Basic .NET]


    • Modificato Alberto De Luca giovedì 2 gennaio 2014 17:37
    • Proposto come risposta Irina Turcu venerdì 10 gennaio 2014 15:59
    • Contrassegnato come risposta Irina Turcu lunedì 13 gennaio 2014 15:23
    • Contrassegno come risposta annullato Lucio Menci mercoledì 15 gennaio 2014 11:05
    • Contrassegnato come risposta Lucio Menci mercoledì 15 gennaio 2014 11:10
    giovedì 2 gennaio 2014 17:34

Tutte le risposte

  • Perchè la comparazione di due oggetti dello stesso tipo presenti nella stessa raccolta basandosi su due input di comparazione diversi è ambigua. Come esplicitato in msdn che ti consiglia di derivare dalla classe Comparer(of T) piuttosto che implementarne l'interfaccia di base. 

    È consigliabile derivare dalla classe Comparer(Of T) anziché implementare l'interfaccia IComparer(T) perché la classe Comparer(Of T) fornisce un'implementazione esplicita dell'interfaccia del metodo IComparer.Compare e della proprietà Default che ottiene l'operatore di confronto predefinito per l'oggetto.

    In altre parole, il metodo Compare vuole avere un'unica implementazione di comparazione per capire se un oggetto è maggiore di un altro, altrimenti rischia di essere una comparazione ambigua. Ti faccio un esempio:

    Oggetto 1

    ID: 1

    Nome: Zanzara

    Oggetto 2

    ID: 2

    Nome: Ape

    Se inseriti all'interno della stessa collection, quale dei due è maggiore? Se analizzi l'ID è maggiore il secondo, se analizzi il nome è maggiore il primo. Ecco da dove nasce l'ambiguità per il compilatore.

    HTH


    Alberto De Luca [MVP - Visual Basic .NET]


    • Modificato Alberto De Luca giovedì 2 gennaio 2014 17:37
    • Proposto come risposta Irina Turcu venerdì 10 gennaio 2014 15:59
    • Contrassegnato come risposta Irina Turcu lunedì 13 gennaio 2014 15:23
    • Contrassegno come risposta annullato Lucio Menci mercoledì 15 gennaio 2014 11:05
    • Contrassegnato come risposta Lucio Menci mercoledì 15 gennaio 2014 11:10
    giovedì 2 gennaio 2014 17:34
  • In questo modo però devo fare:

        Dim CmbStringItemComparer As New _CmbItemComparer(Of String)
        Dim CmbIntItemComparer As New _CmbItemComparer(Of Integer)
        Private Class _CmbItemComparer(Of T)
            Inherits Generic.Comparer(Of CmbItem(Of T, Integer))
    
            Public Overrides Function Compare(x As CmbItem(Of T, Integer), y As CmbItem(Of T, Integer)) As Integer
                Return x.Value.CompareTo(y.Value)
            End Function
        End Class
    

    e dire io nel programma quale dei due oggetti utilizzare (a seconda del tipo di oggetti da confrontare) anziché:

        Dim CmbItemComparer As New _CmbItemComparer
        Private Class _CmbItemComparer
            Implements IComparer(Of CmbItem(Of String, Integer))
            Implements IComparer(Of CmbItem(Of Integer, Integer))
    
            Public Function Compare(x As CmbItem(Of String, Integer), y As CmbItem(Of String, Integer)) As Integer Implements IComparer(Of CmbItem(Of String, Integer)).Compare
                Return x.Value.CompareTo(y.Value)
            End Function
    
            Public Function Compare1(x As CmbItem(Of Integer, Integer), y As CmbItem(Of Integer, Integer)) As Integer Implements IComparer(Of CmbItem(Of Integer, Integer)).Compare
                Return x.Value.CompareTo(y.Value)
            End Function
        End Class
    

    ed utilizzare l'oggetto CmbItemCompare in tutti i punti che lo voglio utilizzare.

    mercoledì 15 gennaio 2014 11:09
  • Certo che lo puoi fare... è soltanto uno warning quello che ti indica il compilatore. Però se tu dovessi utilizzare il tuo oggetto all'interno di una collection legata a funzionalità di oggetti terze parti che utilizzano ICompare (vedi ad esempio l'ordinamento delle colonne di una griglia), potrebbero nascere dei risultati inattesi. Le interfacce sono fantastiche perché ti permettono di comunicare le intenzioni che hai anche ad oggetti che non sanno una mazza della tua logica di implementazione, ma dal momento che accettano oggetti (o che limitano oggetti) che implementano "IQualcosa", dovranno utilizzare i metodi, le proprietà e gli eventi che quella specifica interfaccia definisce.

    HTH


    Alberto De Luca [MVP - Visual Basic .NET]


    mercoledì 15 gennaio 2014 12:37
  • Però se tu dovessi utilizzare il tuo oggetto all'interno di una collection legata a funzionalità di oggetti terze parti che utilizzano ICompare (vedi ad esempio l'ordinamento delle colonne di una griglia), potrebbero nascere dei risultati inattesi. 

    È quello che faccio, ed è per quello che volevo che l'oggetto fosse indipendente dal tipo da ordinare (così non devo indicare oggetti differenti per colonne differenti). Comunque sia, preferisco non vedere warning, così sono sicuro di non avere risultati inattesi. Utilizzerò il primo metodo.

    Grazie

    venerdì 17 gennaio 2014 15:30