2009-07-07 13 views
0

Ich war auf einem Demo-Verfahren zu arbeiten und fand etwas seltsam (zumindest für mich :-))ref Art und Werttyp in Allgemein

enter code here class Program 
{ 
    public void AnotherSwap<T>(T a, T b) 
    { 
     T temp; 
     temp = a; 
     a = b; 
     b = temp; 

     Console.WriteLine(a); 
     Console.WriteLine(b); 

    } 


    public void swap<T>(T a, T b) where T : MyInt // Passing without ref 
    { 
     object temp; 
     temp = a.MyProperty; 
     a.MyProperty = b.MyProperty; 
     b.MyProperty = (int)temp; 

     Console.WriteLine(a.MyProperty); 
     Console.WriteLine(b.MyProperty); 



    } 

    static void Main(string[] args) 
    { 
     Program p = new Program(); 
     MyInt a = new MyInt() { MyProperty = 10 }; 
     MyInt b = new MyInt() { MyProperty = 20 }; 
     p.swap<MyInt>(a, b); 
     Console.WriteLine(a.MyProperty); // changed values get reflected 
     Console.WriteLine(b.MyProperty); // changed values get reflected 

     Console.WriteLine("Another Swap"); 
     object x = 10; 
     object y = 20; 
     p.AnotherSwap(x, y); 

     Console.WriteLine(x); // changed values are not getting reflected 
     Console.WriteLine(y); // changed values are not getting reflected 

     Console.ReadKey(); 


    } 
    public class MyInt 
    { 
     public int MyProperty { get; set; } 

    } 




} 

Hier, wenn ich den Swap nenne(), obwohl ich haven ref nicht erwähnt, werden die geänderten Werte automatisch reflektiert (wie in p.swap (a, b); a und b sind Instanzen von Myint und werden daher standardmäßig als ref..as nach meinem Verständnis funktionieren.) Aber gleich sollte mit Anotherswap() geschehen, hier gebe ich auch Objekt x, y weiter, aber jetzt werden die Werte nicht in Main() .ie widergespiegelt Jetzt arbeitet es als Werttyp. Kann jemand erklären, wo mein Verständnis falsch läuft? Lassen Sie mich wissen, wenn Sie mehr Informationen wünschen.

Antwort

1

Wenn der MyInt-Typ als Objekt umgewandelt wird, wird er als Val-Typ umgewandelt. Objekt kann nicht wie eine Referenz behandelt werden, da es sowohl val als auch ref darstellt, es muss explizit durch ref übergeben werden.

int kann als Objekt umgewandelt werden, und es wird immer noch als val behandelt. Zeichenfolge kann als Objekt umgewandelt und als val behandelt werden. Auch wenn es normalerweise ein Ref-Typ wäre.

Wenn Sie die AnotherSwap ausgeführt und T in als MyInt übergeben haben, erhalten Sie die gleichen Ergebnisse wie zuvor. Wenn Sie den ursprünglichen Swap-Algorithmus mit Objekten aufgerufen haben, erhalten Sie die gleiche Ausgabe wie die Letzteren.

+0

danke Chris, ich habe den Punkt. – Wondering

1

Die zweite Menge der Objekte [object x = 1] wird in int konvertiert, was ein Werttyp ist, da ihr bei der Initialisierung ein int zugewiesen wird. Daher wird sie als int behandelt, was ein Werttyp ist.

Wenn Sie das folgende Snippet ausführen, werden Sie meinen Punkt sehen.

object test = 1; 
Console.Writeline(test.GetType()); 

returns: "typeof (Int32)" 

so der Typ Ihres object ist nicht mehr Objekt, sondern Int32, die ein Werttyp ist.

object test = 1; 
Console.Writeline(test.GetType().IsByRef); 

returns: "false" 
+0

IsByRef ist kein Test, ob ein Typ ein Referenztyp ist oder nicht - er wird verwendet, um zu sehen, ob ein Parametertyp * durch * Referenz übergeben wurde. Sie sind sehr unterschiedliche Dinge. typeof (Objekt) .IsByRef ist immer noch falsch ... –

+0

danke, wusste das nicht. Aber ist diese Art der Einblendung dieser Eigenschaft nicht unter Type-Klasse nicht sinnvoll, sollte das nicht Teil des Reflection-Namespace sein? –

3

Ihre Frage ist irreführend, und die Antwort ist eigentlich einfacher als das:

In Ihrer Swap-Funktion, können Sie die Werte der MyProperty Eigenschaften in diesen Klassen tauschen, nicht die eigentlichen Klassen selbst. Dies wäre leicht zu beweisen, wenn Sie eine andere Eigenschaft in der MyInt-Klasse namens "Name" oder etwas hätten. Nach dem Aufruf von Swap sehen Sie, dass die Eigenschaft Name unverändert geblieben ist. Der Grund dafür, dass in AnotherSwap nichts Interessantes passiert, ist, dass Sie die Typen nicht mit ref übergeben. Daher ändern die Zuweisungen, die Sie an den Zeiger des Objekts in der Funktion ausführen, nicht die Zeiger der ursprünglichen Objekte die Perspektive des Anrufers.

Etwas anderes ist zu beachten, dass wenn Sie 10 in ein Objekt verwandeln, Sie das Objekt tatsächlich boxen, und das ist etwas anderes, das Sie im Auge behalten sollten. Wenn Sie Generika schreiben, die sich bei Referenz- und Werttypen anders verhalten sollen, verwende ich immer nur "where T: class" für Referenztypen und "where T: struct" für Werttypen. Die Namen der beiden Funktionen können jedoch nicht identisch sein.