2012-02-14 18 views
9

Quando si lavora con la classe List da System.Collections.Generic, metodi come Contains o IndexOf confronteranno l'oggetto del riferimento passato utilizzando il metodo Equals implementato da IEquatable o il metodo Equals sovrascritto fornito dalla classe Object. Se Object.Equals non viene sovrascritto, controllerà se i punti di riferimento passati hanno lo stesso oggetto di se stesso.Confronta per riferimento?

La mia domanda è: c'è un modo di confrontare Lista per riferimento se uguale è sovrascritto? Il codice qui sotto vi rimuovere la voce dalla lista:

class Program 
{ 
    static void Main(string[] args) 
    {  
     var s1 = new SomeClass() { A = 5 }; 
     var s2 = new SomeClass() { A = 5 }; 
     var list = new List<SomeClass>(); 
     list.Add(s1); 
     list.Remove(s2); // s1 will get removed, even though s2 has been 
         // passed, because s1's Equals method will return true. 

    } 
} 

class SomeClass 
{ 
    public int A { get; set; } 

    public override bool Equals(object obj) 
    { 
     SomeClass s = obj as SomeClass; 
     if (s == null) 
     { 
      return false; 
     } 
     else 
     { 
      return s.A == this.A; 
     } 
    } 
} 

Diciamo che io sono in grado di rimuovere l'attuazione SomeClass' di uguali, c'è un modo di fare la lista confronta con riferimento al posto del valore?

risposta

13

È possibile utilizzare List.RemoveAll e nel proprio predicato, confrontare gli articoli con Object.ReferenceEquals.

list.RemoveAll(item => object.ReferenceEquals(item, s2)); 

Il codice ha rimosso correttamente i 1 elementi durante il debug da Visual Studio 2010 Express.

+0

Grazie, sembra funzionare bene. – haiyyu

4

La soluzione di Austin è semplice e funzionante. Ma ecco anche due metodi di estensione generici:

items.RemoveAllByReference(item); 

public static void RemoveAllByReference<T>(this List<T> list, T item) 
{ 
    list.RemoveAll(x=> object.ReferenceEquals(x, item)); 
} 

public static bool RemoveFirstByReference<T>(this List<T> list, T item) 
{ 
    var index = -1; 
    for(int i = 0; i< list.Count; i++) 
     if(object.ReferenceEquals(list[i], item)) 
     { 
      index = i; 
      break; 
     } 
    if(index == -1) 
     return false; 

    list.RemoveAt(index); 
    return true; 
} 
+0

Interessante, ma perché questo è più ottimale - non è simile a ciò che il predicato fa internamente? Mi piacerebbe sapere il tuo ragionamento ... –

+0

E se l'oggetto è nella lista n volte? –

+0

Il metodo di Austin controlla sempre tutti gli elementi. Questo rompe il loop quando ne trova uno. Ma ora, quando ci penso, potrebbe essere più corretto cercare l'intero elenco e rimuovere tutte le istanze dello stesso elemento in un elenco ... Quindi dipende da ciò che vuoi. Tuttavia, un metodo di estensione è un vantaggio se lo si utilizza in più punti. – doblak