2015-05-17 3 views
5

Ich habe diesen Code, der den Wert aus der Klasse Test erhält und dann in den Typ konvertiert, der es ist. Es wird korrekt als "Int32" gedruckt, aber wenn ich die Gleichheit mit einer anderen Variablen mit demselben Wert teste, wird "false" ausgegeben. Ich vermute, es liegt daran, dass es Referenzgleichheit testet und dass die 2 Variablen wirklich noch Objekte sind. Gibt es eine Möglichkeit, sie zu vergleichen, wenn ich bedenke, dass ich den Typ des zurückgegebenen Werts bis zur Laufzeit nicht kenne (es könnte eine Zeichenfolge, Float, andere Klasse usw. sein)?Wie kann ich die aus Reflection "GetValue" ermittelten Werttypen vergleichen?

class Test{public int y;} 

static void Main() 
{ 
    var test1 = new Test{y=1}; 
    var test2 = new Test{y=1}; 
    var fields = test1.GetType().GetFields(); 
    var test1Value = fields[0].GetValue(test1); 
    var test2Value = fields[0].GetValue(test2); 
    var test1Converted = Convert.ChangeType(test1Value, test1Value.GetType()); 
    var test2Converted = Convert.ChangeType(test2Value, test2Value.GetType()); 
    Console.WriteLine(test1Converted); // prints Int32 
    Console.WriteLine(test1Converted == test2Converted); // prints false 
} 

Antwort

3

Die Aufrufe an Convert sind nicht erforderlich. Die von GetValue zurückgegebenen Werte sind bereits int s. Sie einfach zu werfen gibt das richtige Ergebnis.

private class Test 
{ 
    public int y; 
} 

private static void Main() 
{ 
    Test test1 = new Test { y = 1 }; 
    Test test2 = new Test { y = 1 }; 
    FieldInfo[] fields = test1.GetType().GetFields(); 
    int test1Value = (int)fields[0].GetValue(test1); 
    int test2Value = (int)fields[0].GetValue(test2); 
    Console.WriteLine(test1Value); // prints Int32 
    Console.WriteLine(test1Value == test2Value); // prints true 
} 

Der Grund, dass die UN-gegossenen Werte versagt ist, dass Convert.ChangeType noch eine object zurückgibt, die die Ints boxes, so dass man in der Tat Referenz Gleichheit erhalten haben.

Ein anderer Weg, um den richtigen Wert zu erhalten, ist die Equals Methode aufzurufen, die korrekt zu Int32.Equals geleitet werden, und drucken true:

Console.WriteLine(test1Converted.Equals(test2Converted)); // prints true 

Beachten Sie in diesem Fall, dass die Convert.ChangeType noch nicht notwendig ist.

+1

Equals für die Referenz versagen Typen, hier ist es erfolgreich für den Wert/Integer-Typ, wie es der Wert Vergleich tut, erfordert dies explizite überschreiben der Equals-Methode –

+1

@MrinalKamboj Können Sie ein konkretes Beispiel geben, wo ein Referenztyp fehlschlagen würde? Alle Referenztypen * bereits * werden standardmäßig auf Referenzgleichheit gesetzt und nicht mit GetValue umrahmt. –

+0

Wie Sie vorgeschlagen haben, bezieht sich Reference equals auf die Referenzgleichheit. Für die Equals-Standardmethode ist es nicht erforderlich, dass zwei über Reflektion abgerufene Referenztypen auf dieselbe Referenz verweisen. Um den intrinsischen Wert zu vergleichen, müsste die Equals-Methode explizit überschrieben werden für die aktuelle Antwort –

1

Convert.ChangeType() gibt das Objekt zurück. Cast das zurückgegebene Objekt zu Int32:

var test1Converted = (Int32)Convert.ChangeType(test1Value, test1Value.GetType()); 
    var test2Converted = (Int32)Convert.ChangeType(test2Value, test2Value.GetType()); 

Einfüg.Nummer Kommentar: -Test, wenn der Typ IComparable ist, und verwenden Sie dann diese Schnittstelle den Vergleich zu tun:

if (test1Converted is IComparable && test2Converted is IComparable) 
    { 
     var test1IComparable = (IComparable)test1Converted; 
     var test2IComparable = (IComparable)test2Converted; 

     bool equal = (test1IComparable == test2IComparable); 
    } 
+0

Ich kann nicht casten, weil ich nicht weiß was der Typ des Objekts bis zur Laufzeit ist. Es könnte eine Zeichenfolge oder eine andere Klasse sein. –

+0

Ah, richtig, na dann wird es komplizierter :) Sie können testen, ob die Werte IComparable sind; Ist dies der Fall, wird in IComparable und dann in CompareTo (andere) umgewandelt. – glenebob

+0

@SupremeGrandRuler: Wenn Sie möchten, dass '32f' gleich' 32L' ist, haben Sie Probleme. Andernfalls rufen Sie einfach Equals() 'auf. – SLaks

-1

In meinem Verständnis Hauptproblem hier draußen Ist Ihnen das Feld Testtypklasse bis zur Laufzeit nicht bekannt, und vermeiden Sie eine explizite Typumwandlung in einen Integer-Typ. So vergleichen wir zwischen zwei Objekten test1Converted und test2Converted, einfacher Weg würde überschreiben die Equals-Methode des Objekt-Basistyps, die in == Vergleich aufgerufen wird. Im aktuellen Fall test1Converted.Equals(test2Converted) funktionieren würde, aber wenn Sie Referenztypen haben, dann müssen Sie die Equals-Methode überschreiben, für korrektes Ergebnis, falls es nur Werttypen sind, dann gibt es kein Problem

+0

Sie beantworten eine Frage, die nicht vom OP gestellt wurde. Sie müssen bei Nicht-Referenztypen immer 'Equals' überschreiben, um eine Wertgleichheit zu erhalten, aber das hat nichts mit der tatsächlich gestellten Frage zu tun. –

+0

@Jason Watkins Es gibt keinen Grund zu Downvote, meine Antwort bietet die richtige Antwort mit der Aussage, Equals kann verwendet werden und in der Tat sogar berühren Sie den Referenztyp in einer Klasse, zeigen Sie das Problem in der Antwort, nicht eine gute Sache zu down vote an einem Tropfen einer Nadel –

+0

Für den zweiten down Wähler auch, wahrscheinlich haben Sie die Antwort nicht verstanden, lesen Sie es und weisen Sie auf den Fehler, es beantwortet genau die Frage und geht darüber hinaus –

Verwandte Themen