Differenza C # tra == e Equals ()


548

Ho una condizione in un'applicazione silverlight che confronta 2 stringhe, per qualche motivo quando lo uso ==restituisce false mentre .Equals()restituisce true .

Ecco il codice:

if (((ListBoxItem)lstBaseMenu.SelectedItem).Content.Equals("Energy Attack"))
{
    // Execute code
}

if (((ListBoxItem)lstBaseMenu.SelectedItem).Content == "Energy Attack")
{
    // Execute code
}

Qualche motivo per cui questo sta accadendo?



8
La stringa ha la precedenza ==, ma gli operatori non sono polimorfici. In questo codice, l' ==operatore viene richiamato sul tipo object, che esegue un confronto di identità anziché un valore.
Drew Noakes,

12
Per espandere il commento di @DrewNoakes: Il compilatore sceglie un ==sovraccarico in base al tipo di tempo di compilazione degli operandi. La Contentproprietà è object. Gli operatori non sono virtuali, pertanto ==viene chiamata l' implementazione predefinita di , fornendo un confronto di uguaglianza di riferimento. Con Equals, la chiamata passa al metodo virtuale object.Equals(object); stringignora questo metodo ed esegue un confronto ordinale sul contenuto della stringa. Vedere msdn.microsoft.com/en-us/library/fkfd9eh8(v=vs.110).aspx e riferimentiource.microsoft.com/#mscorlib/system/string.cs.507 .
phoog

6
La spiegazione di @ phoog è precisa. Va notato che quando il lato sinistro di ==ha il tipo di tempo di compilazione objecte il lato destro ha il tipo di tempo di compilazione string, il compilatore C # deve scegliere il sovraccarico (problematico, in questo caso) operator ==(object, object); ma sarà un avvertimento in fase di compilazione che potrebbe essere intenzionale. Quindi leggi gli avvisi in fase di compilazione! Per risolvere il problema e continuare a utilizzarlo ==, eseguire il cast del lato sinistro su string. Se ricordo bene, il testo di avvertimento suggerisce proprio questo.
Jeppe Stig Nielsen,

1
@JeppeStigNielsen +1 per il consiglio di leggere gli avvisi del compilatore. Ancora meglio: attiva l'opzione avvertimenti come errori per costringere tutti a prestare attenzione a loro.
phoog

Risposte:


429

Quando ==viene utilizzato su un'espressione di tipo object, si risolverà in System.Object.ReferenceEquals.

Equalsè solo un virtualmetodo e si comporta come tale, quindi verrà utilizzata la versione sovrascritta (che, per stringtipo, confronta i contenuti).


57
A meno che l'operatore non sia specificamente implementato nella classe
Dominic Cronin,

23
@DominicCronin Questo non è vero. Anche se == è implementato nella classe, verrà ignorato perché il tipo a sinistra del confronto è oggetto. Sembra che i sovraccarichi dell'operatore siano determinati in fase di compilazione e in fase di compilazione tutto ciò che sa è che il lato sinistro è un oggetto.
MikeKulls,

4
@DominicCronin Credo che la tua prima affermazione sia corretta in quanto == risolverà per obiettare, ma la tua seconda affermazione che i sovraccarichi dell'operatore si risolvono in un modo simile non lo è. Sono abbastanza diversi ed è per questo che .Equals si risolveranno in stringa mentre == si risolveranno in oggetto.
MikeKulls,

8
Per essere chiari, objectdigitare (notare il carattere monospace) è tecnicamente inteso come "un'espressione di tipo System.Object". Non ha nulla a che fare con il tipo di runtime dell'istanza a cui fa riferimento l'espressione. Penso che l'affermazione "gli operatori definiti dall'utente sono trattati come virtualmetodi" sia estremamente fuorviante. Sono trattati come metodi sovraccarichi e dipendono solo dal tipo di tempo di compilazione degli operandi. Infatti, dopo che è stata calcolata la serie di operatori definiti dall'utente candidati, il resto della procedura di associazione sarà esattamente l'algoritmo di risoluzione del sovraccarico del metodo
Mehrdad Afshari,

4
@DominicCronin La parte fuorviante è che la virtualrisoluzione del metodo dipende dal tipo di runtime effettivo di un'istanza, mentre ciò è completamente ignorato nella risoluzione di sovraccarico dell'operatore e questo è in effetti il ​​punto della mia risposta.
Mehrdad Afshari,

314

Quando si confronta un riferimento a un oggetto con una stringa (anche se il riferimento a un oggetto si riferisce a una stringa), il comportamento speciale ==dell'operatore specifico della classe di stringa viene ignorato.

Normalmente (quando non si tratta di stringhe, cioè), Equalsconfronta i valori , mentre ==confronta i riferimenti agli oggetti . Se due oggetti che stai confrontando si riferiscono alla stessa esatta istanza di un oggetto, entrambi restituiranno true, ma se uno ha lo stesso contenuto e proviene da un'origine diversa (è un'istanza separata con gli stessi dati), solo Equals lo farà ritorna vero. Tuttavia, come notato nei commenti, la stringa è un caso speciale perché sovrascrive l' ==operatore in modo che quando si tratta esclusivamente di riferimenti a stringa (e non a riferimenti a oggetti), vengono confrontati solo i valori anche se sono istanze separate. Il codice seguente illustra le sottili differenze nei comportamenti:

string s1 = "test";
string s2 = "test";
string s3 = "test1".Substring(0, 4);
object s4 = s3;
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s2), s1 == s2, s1.Equals(s2));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s3), s1 == s3, s1.Equals(s3));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s4), s1 == s4, s1.Equals(s4));

L'output è:

True True True
False True True
False False True

8
Spot on. L'operatore '==' confronta i riferimenti agli oggetti (confronto superficiale) mentre .Equals () confronta il contenuto degli oggetti (confronto approfondito). Come diceva @mehrdad, .Equals () viene ignorato per fornire un confronto approfondito dei contenuti.
Andrew,

1
Lascerò il post qui perché penso che sia utile sottolineare ciò che non sta accadendo poiché devi prestare molta attenzione per realizzarlo. (E penso che
valga la

5
Sicuramente String implementa un operatore == personalizzato. In caso contrario, l'utilizzo di == non confronta il contenuto. Quindi String è un cattivo esempio da usare qui, poiché non ci aiuta a capire il caso generale in cui non è stato definito alcun operatore personalizzato.
Dominic Cronin,

6
+1 per l'esempio di codice epico, che mi ha fatto capire questo. Mostra il caso generale del tipo statico (tipo lato sinistro) come oggetto e il caso specifico del tipo statico (/ tipo RHS) è stringa. E tocca bene lo string interning.
barlop

2
@badsamaritan A causa dell'internamento delle stringhe
Alexander Derck,

46

==e .Equalsdipendono entrambi dal comportamento definito nel tipo effettivo e dal tipo effettivo nel sito di chiamata. Entrambi sono solo metodi / operatori che possono essere sovrascritti su qualsiasi tipo e dato qualsiasi comportamento l'autore desideri. Nella mia esperienza, trovo che per le persone sia comune implementare .Equalsun oggetto ma trascurare l'implementazione dell'operatore ==. Ciò significa che .Equalsmisurerà effettivamente l'uguaglianza dei valori mentre ==misurerà se sono o meno lo stesso riferimento.

Quando lavoro con un nuovo tipo la cui definizione è in evoluzione o quando scrivo algoritmi generici, trovo che la migliore pratica sia la seguente

  • Se voglio confrontare i riferimenti in C #, uso Object.ReferenceEqualsdirettamente (non necessario nel caso generico)
  • Se voglio confrontare i valori che uso EqualityComparer<T>.Default

In alcuni casi, quando ritengo che l'uso di ==sia ambiguo, userò esplicitamente Object.Referenceuguali nel codice per rimuovere l'ambiguità.

Eric Lippert ha recentemente pubblicato un post sul blog sul motivo per cui ci sono 2 metodi di uguaglianza nel CLR. Vale la pena leggere


Bene, Jared, hai violato direttamente il famoso Jeff "Il miglior codice non è affatto un codice qui". È davvero giustificato? D'altra parte, posso vedere da dove proviene e perché potrebbe essere desiderabile rendere esplicita la semantica. In questo caso, preferisco di gran lunga il modo in cui VB tratta l'uguaglianza degli oggetti. È breve e inequivocabile.
Konrad Rudolph,

@Konrad, avrei davvero dovuto dire "quando non ho familiarità con un tipo, trovo che la migliore pratica sia la seguente". Sì, VB ha una semantica molto migliore qui perché separa veramente l'uguaglianza tra valore e riferimento. C # mescola i due elementi e occasionalmente causa errori di ambiguità.
JaredPar,

10
Questo non è del tutto vero. == non può essere ignorato, è un metodo statico. Può solo essere sovraccarico, che è una differenza importante. Quindi il codice che viene eseguito per un operatore == è collegato al momento della compilazione, mentre Equals è virtuale e trovato al momento dell'esecuzione.
Stefan Steinegger,

20

== Operatore

  1. Se gli operandi sono Tipi di valore e i loro valori sono uguali, restituisce true altrimenti false.
  2. Se gli operandi sono Tipi di riferimento con l'eccezione della stringa ed entrambi si riferiscono alla stessa istanza (stesso oggetto), restituisce true else false.
  3. Se gli operandi sono di tipo stringa e i loro valori sono uguali, restituisce true else false.

.È uguale a

  1. Se gli operandi sono Tipi di riferimento , esegue l' Uguaglianza di riferimento, ovvero se entrambi si riferiscono alla stessa istanza (stesso oggetto), restituisce true altrimenti false.
  2. Se gli operandi sono tipi di valore, a differenza dell'operatore == verifica prima il loro tipo e se i loro tipi sono uguali esegue l'operatore == altrimenti restituisce false.

2
Questo non è corretto L' ==operatore può essere sovraccaricato per qualsiasi tipo, non solo per la stringa. Descrivere un'eccezione di un caso speciale solo per stringa travisa la semantica dell'operatore. Sarebbe più preciso, anche se forse non estremamente utile, dire "se gli operandi sono tipi di riferimento restituisce vero se gli operandi si riferiscono allo stesso oggetto, a meno che non vi sia un sovraccarico applicabile, nel qual caso l'implementazione di quel sovraccarico determina il risultato ". Lo stesso vale Equalscon l'ulteriore complicazione che si tratta di un metodo virtuale, quindi il suo comportamento può essere ignorato o sovraccaricato.
phoog

19

In primo luogo, c'è una differenza. Per i numeri

> 2 == 2.0
True

> 2.Equals(2.0)
False

E per archi

> string x = null;
> x == null
True

> x.Equals(null)
NullReferenceException

In entrambi i casi, ==si comporta in modo più utile di.Equals


2
Non sono sicuro che considererei la coercizione di tipi integrali a tipi a virgola mobile con l' ==operatore come una buona cosa. Ad esempio, 16777216.0f dovrebbe essere uguale (int) 16777217, (doppio) 16777217,0, entrambi o nessuno dei due? I confronti tra tipi integrali vanno bene, ma i confronti in virgola mobile devono essere eseguiti solo IMHO con valori espressi in modo esplicito su tipi corrispondenti. Il confronto tra floata qualcosa di diverso da a float, o doublea qualcosa di diverso da a double, mi sembra un odore di codice importante che non dovrebbe essere compilato senza diagnostica.
supercat

1
@supercat Sono d'accordo - è angosciante che x == ynon implica x/3 == y/3(prova x = 5e y = 5.0).
Colonnello Panic,

Considero l'uso della /divisione integer come un difetto nella progettazione di C # e Java. Pascal dive anche VB.NET ` are much better. The problems with == `sono peggio, però: x==ye y==znon implica questo x==z(considerate i tre numeri nel mio commento precedente). Per quanto riguarda la relazione che suggerisci, anche se xe ysono entrambi floato entrambi double, x.equals((Object)y)non implica che 1.0f/x == 1.0f / y` (se avessi i miei druther, lo garantirebbe; anche se ==non distinguo positivo e zero, Equalsdovrebbe).
supercat

È normale, perché il primo parametro di Equals () è una stringa!
Whiplash,

17

Per quanto ho capito, la risposta è semplice:

  1. == confronta i riferimenti agli oggetti.
  2. .Equals confronta il contenuto dell'oggetto.
  3. String i tipi di dati fungono sempre da confronto dei contenuti.

Spero di aver ragione e che abbia risposto alla tua domanda.


15

Aggiungo che se lanci il tuo oggetto su una stringa, funzionerà correttamente. Questo è il motivo per cui il compilatore ti darà un avviso dicendo:

Possibile confronto di riferimento non intenzionale; per ottenere un confronto di valori, esegui il cast del lato sinistro per digitare "stringa"


1
Esattamente. @DominicCronin: osservare sempre gli avvisi in fase di compilazione. In tal caso object expr = XXX; if (expr == "Energy") { ... }, poiché il lato sinistro è di tipo tempo di compilazione object, il compilatore deve utilizzare il sovraccarico operator ==(object, object). Verifica l'uguaglianza di riferimento. Se ciò darà trueo falsepuò essere difficile da prevedere a causa dell'internazionalizzazione delle stringhe . Se sai che il lato sinistro è uno nullo del tipo string, getta il lato sinistro stringprima dell'uso ==.
Jeppe Stig Nielsen,

per dirla in un altro modo. == (nel determinare se utilizza l'uguaglianza di riferimento o l'uguaglianza di valore) dipende dal tipo di tempo di compilazione / dal tipo statico / dal lato sinistro. (questo è il tipo che viene risolto in un'analisi del tempo di compilazione). Piuttosto che il tipo di runtime / tipo dinamico / tipo RHS. Il codice di BlueMonkMN lo dimostra, sebbene non con il casting.
barlop

5

Poiché la versione statica del .Equalmetodo non è stata menzionata finora, vorrei aggiungerla qui per riassumere e confrontare le 3 varianti.

MyString.Equals("Somestring"))          //Method 1
MyString == "Somestring"                //Method 2
String.Equals("Somestring", MyString);  //Method 3 (static String.Equals method) - better

dove MyStringè una variabile che proviene da qualche altra parte nel codice.

Informazioni di base e per effettuare l'estate:

In Java ==non è necessario utilizzare il confronto per stringhe. Ne parlo nel caso in cui sia necessario utilizzare entrambe le lingue e anche per farti sapere che l'utilizzo ==può anche essere sostituito con qualcosa di meglio in C #.

In C # non c'è alcuna differenza pratica per confrontare le stringhe usando il Metodo 1 o il Metodo 2 purché entrambi siano di tipo stringa. Tuttavia, se uno è nullo, uno è di un altro tipo (come un numero intero) o rappresenta un oggetto con un riferimento diverso, quindi, come mostra la domanda iniziale, potresti riscontrare che il confronto del contenuto per l'uguaglianza potrebbe non restituire ciò che ti aspetti.

Soluzione suggerita:

Poiché l'utilizzo ==non è esattamente uguale all'utilizzo .Equalsquando si confrontano le cose, è possibile utilizzare invece il metodo String.Equals statico . In questo modo, se i due lati non sono dello stesso tipo, si confronteranno comunque i contenuti e se uno è nullo, si eviterà l'eccezione.

   bool areEqual = String.Equals("Somestring", MyString);  

È un po 'di più da scrivere, ma secondo me è più sicuro da usare.

Ecco alcune informazioni copiate da Microsoft:

public static bool Equals (string a, string b);

parametri

a Corda

La prima stringa da confrontare, o null.

b Corda

La seconda stringa da confrontare, o null.

ritorna Boolean

truese il valore di aè uguale al valore di b; in caso contrario, false. Se entrambi ae lo bsono null, il metodo ritorna true.


5

Proprio come un'aggiunta alle già buone risposte: questo comportamento NON è limitato alle stringhe o al confronto di diversi tipi di numeri. Anche se entrambi gli elementi sono di tipo oggetto dello stesso tipo sottostante. "==" non funzionerà.

La seguente schermata mostra i risultati del confronto tra due valori {int} - object

Esempio da VS2017


2

Sono un po 'confuso qui. Se il tipo di runtime di Content è di tipo string, allora sia == che Equals dovrebbero restituire true. Tuttavia, poiché questo non sembra essere il caso, il tipo di runtime di Content non è una stringa e la chiamata Equals su di esso sta facendo un'uguaglianza referenziale e questo spiega perché Equals ("Energy Attack") fallisce. Tuttavia, nel secondo caso, la decisione su quale sovraccarico == operatore statico dovrebbe essere chiamato viene presa al momento della compilazione e questa decisione sembra essere == (stringa, stringa). questo mi suggerisce che il contenuto fornisce una conversione implicita in stringa.


2
Lo hai di nuovo in primo piano. Per cominciare, Equals ("Energy Attack") non fallisce, == è quello che restituisce false. == ha esito negativo poiché utilizza == dall'oggetto, non dalla stringa.
MikeKulls,

Per impostazione predefinita, l'operatore == verifica l'uguaglianza di riferimento determinando se due riferimenti indicano lo stesso oggetto. Pertanto, i tipi di riferimento non devono implementare operator == per ottenere questa funzionalità. Quando un tipo è immutabile, cioè i dati contenuti nell'istanza non possono essere modificati, sovraccaricare l'operatore == per confrontare l'uguaglianza di valore anziché l'uguaglianza di riferimento può essere utile perché, come oggetti immutabili, possono essere considerati uguali a lungo in quanto hanno lo stesso valore. Non è una buona idea sostituire l'operatore == in tipi non immutabili.
Wajeed-MSFT,

2

C'è un'altra dimensione in una risposta precedente di @BlueMonkMN. La dimensione aggiuntiva è che la risposta alla domanda sul titolo di @ Drahcir, come viene affermato, dipende anche da come siamo arrivati ​​al stringvalore. Illustrare:

string s1 = "test";
string s2 = "test";
string s3 = "test1".Substring(0, 4);
object s4 = s3;
string s5 = "te" + "st";
object s6 = s5;
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s2), s1 == s2, s1.Equals(s2));

Console.WriteLine("\n  Case1 - A method changes the value:");
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s3), s1 == s3, s1.Equals(s3));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s4), s1 == s4, s1.Equals(s4));

Console.WriteLine("\n  Case2 - Having only literals allows to arrive at a literal:");
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s5), s1 == s5, s1.Equals(s5));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s6), s1 == s6, s1.Equals(s6));

L'output è:

True True True

  Case1 - A method changes the value:
False True True
False False True

  Case2 - Having only literals allows to arrive at a literal:
True True True
True True True

2

Aggiungendo un altro punto alla risposta.

.EqualsTo() Il metodo ti fornisce la possibilità di confrontare con cultura e maiuscole e minuscole.


0

Il ==token in C # viene utilizzato per due diversi operatori di controllo dell'uguaglianza. Quando il compilatore incontra quel token, verificherà se uno dei tipi confrontati ha implementato un sovraccarico operatore-uguaglianza per i tipi di combinazione specifici da confrontare (*) o per una combinazione di tipi in cui entrambi i tipi possono essere convertiti. Se il compilatore rileva un tale sovraccarico, lo utilizzerà. Altrimenti, se i due tipi sono entrambi tipi di riferimento e non sono classi non correlate (o possono essere un'interfaccia o possono essere classi correlate), il compilatore considererà ==un operatore di confronto di riferimento. Se nessuna delle due condizioni si applica, la compilazione fallirà.

Si noti che alcune altre lingue usano token separati per i due operatori di controllo dell'uguaglianza. In VB.NET, ad esempio, il =token viene utilizzato all'interno delle espressioni esclusivamente per l'operatore di verifica dell'uguaglianza sovraccaricabile e Isviene utilizzato come operatore di test di riferimento o test null. L'uso =da parte di un tipo che non prevale sull'operatore di verifica dell'uguaglianza fallirà, così come il tentativo di utilizzare Isper scopi diversi dalla verifica dell'uguaglianza o della nullità di riferimento.

(*) I tipi generalmente sovraccaricano l'uguaglianza solo per il confronto con se stessi, ma può essere utile per i tipi sovraccaricare l'operatore di uguaglianza per il confronto con altri tipi particolari; per esempio, intavrebbe potuto (e IMHO avrebbe dovuto, ma non avrebbe), definito un operatore di uguaglianza per il confronto float, in modo che 16777217 non si riferisse a pari a 16777216f. Così com'è, poiché non viene definito alcun operatore di questo tipo, C # promuoverà il intto float, arrotondandolo a 16777216f prima che l'operatore di controllo dell'uguaglianza lo veda; quell'operatore vede quindi due numeri uguali in virgola mobile e li riporta come uguali, ignari dell'arrotondamento che ha avuto luogo.


Piuttosto che avere un confronto int-float restituire false, preferisco l'approccio che F # usa, che è di non consentire affatto un simile confronto. Quindi il programmatore può decidere se e come gestire il fatto che i valori abbiano tipi diversi. Perché a volte, dopo tutto, noi fare vogliamo trattare 3come essere uguale a 3.0f. Se chiediamo al programmatore di dire ciò che è previsto in ogni caso, allora non c'è pericolo che un comportamento predefinito porti a risultati indesiderati, poiché non esiste un comportamento predefinito.
phoog

@phoog: la mia sensazione personale è che le lingue dovrebbero avere i loro "normali" mezzi per test di uguaglianza implementare una relazione di equivalenza e proibire tutte le combinazioni di operandi per le quali non lo sarebbero. Non vedo un enorme vantaggio di avere un controllo del linguaggio sull'uguaglianza tra numeri interi e float confermando che un float rappresenta esattamente un numero intero che corrisponde all'int, rispetto al semplice divieto di tali confronti, ma considererebbe entrambi gli approcci superiori rispetto all'esecuzione del linguaggio una conversione con perdite prima del confronto.
supercat

0

Risposte ed esempi davvero fantastici!

Vorrei solo aggiungere la differenza fondamentale tra i due,

Operatori come ==non sono polimorfici, mentre lo Equalsè

Con questo concetto in mente, se elaborate qualche esempio (osservando il tipo di riferimento della mano sinistra e della destra e verificando / sapendo se il tipo ha effettivamente == l'operatore è sovraccarico e gli uguali vengono sostituiti) siete sicuri di ottenere la risposta giusta .



-2

==

L'operatore == può essere utilizzato per confrontare due variabili di qualsiasi tipo e confronta semplicemente i bit .

int a = 3;
byte b = 3;
if (a == b) { // true }

Nota: ci sono più zeri sul lato sinistro dell'int ma non ci interessa a questo.

int a (00000011) == byte b (00000011)

Ricorda che l'operatore == si preoccupa solo del modello dei bit nella variabile.

Utilizzare == Se due riferimenti (primitivi) si riferiscono allo stesso oggetto nell'heap.

Le regole sono le stesse indipendentemente dal fatto che la variabile sia un riferimento o una primitiva.

Foo a = new Foo();
Foo b = new Foo();
Foo c = a;

if (a == b) { // false }
if (a == c) { // true }
if (b == c) { // false }

a == c è vero a == b è falso

il modello di bit è lo stesso per a e c, quindi sono uguali usando ==.

Pari():

Usa il metodo equals () per vedere se due oggetti diversi sono uguali .

Come due diversi oggetti String che rappresentano entrambi i personaggi in "Jane"


2
Questo non è corretto Si consideri il seguente: object a = 3; object b = 3; Console.WriteLine(a == b);. L'output è falso, anche se i modelli di bit dei valori sono gli stessi. Anche i tipi di operandi contano. Il motivo per cui "non ci interessa" del diverso numero di zeri nel tuo esempio è che quando chiamiamo l'operatore uguale, il numero di zeri è effettivamente lo stesso , a causa della conversione implicita.
phoog

-2

L'unica differenza tra Equal e == sta nel confronto del tipo di oggetto. in altri casi, come tipi di riferimento e tipi di valore, sono quasi uguali (entrambi sono uguaglianza bit-bit o entrambi sono uguaglianza di riferimento).

oggetto: uguale: uguaglianza bit = = uguaglianza di riferimento

string: (equals e == sono gli stessi per string, ma se una delle string cambia in oggetto, il risultato del confronto sarà diverso) Equals: uguaglianza bit-bit = =: uguaglianza bit-saggio

Vedi qui per ulteriori spiegazioni.


Object.Equals non considera necessariamente l'uguaglianza bit a bit. È un metodo virtuale e una sostituzione può fare quello che vuole.
phoog

sì, hai ragione, puoi fare tutto ciò che vuoi scavalcarlo. ma l'argomento di cui stiamo parlando è l'implementazione predefinita. l'implementazione predefinita di Object.Equals è l'uguaglianza bit-saggia.
Will Yu
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.