2015-10-10 16 views
7

Nach meinem Wissen this in einer Erweiterung Methode als ref Variable übergeben wird. Ich kann dies überprüfen, indemErweiterungsmethode und lokale 'diese' Variable

public static void Method<T>(this List<T> list) 
{ 
    list.Add(default(T)); 
} 

List<int> ints = new List<int>(new int[] { 1, 2, 3, 4, 5 }); 
ints.Method(); 

Mein List<int> ints tun jetzt 1, 2, 3, 4, 5, 0 ist.

aber wenn ich

public static void Method<T>(this List<T> list, Func<T, bool> predicate) 
{ 
    list = list.Where(predicate).ToList(); 
} 

List<int> ints = new List<int>(new int[] { 1, 2, 3, 4, 5 }); 
ints.Method(i => i > 2); 

würde ich meine List<int> ints erwarten 3, 4, 5 zu sein, aber bleibt unberührt. Fehle ich etwas Offensichtliches?

+0

'list' nicht als Referenz übergeben wird, es ist eine Referenz von Wert übergeben

Also in Ihrem zweiten Fall sollten Sie verwenden. Alias-Referenz gibt die Variable in der aufrufenden Methode innerhalb des Aufrufers an, die Sie direkt zuweisen können. – Lee

+0

Es gibt einen Unterschied zwischen "Übergabe * durch * Referenz" und "Weitergabe * a * Referenz". Der Verweis auf die Liste wird als Wert übergeben, dh Sie können auf die Liste zugreifen und sie ändern, aber Sie berühren nicht die externe Variable, die ebenfalls auf die Liste verweist. –

+0

'(neue Liste ()). Methode()' compiles => Argument muss überhaupt keine Variable sein => nicht wie 'ref'. –

Antwort

5

Der Erweiterungsmethode-Parameterwird als Wert übergeben, nicht als Referenz. Dies bedeutet, dass Sie beim Eingeben der Erweiterungsmethode zwei Variablen haben, die auf die gleiche Speicheradresse zeigen: den ursprünglichen ints und den list Parameter. Wenn Sie der Liste innerhalb der Erweiterungsmethode ein Element hinzufügen, wird dies in ints widergespiegelt, da Sie ein Objekt ändern, auf das beide Variablen verweisen. Wenn Sie list neu zuweisen, wird eine neue Liste auf dem verwalteten Heap erstellt, und der Parameter der Erweiterungsmethode verweist auf diese Liste. Die Variable ints verweist immer noch auf die alte Liste.

3

Nun, wenn Sie versuchen, die Eigenschaft einer Klasseninstanz zu ändern, brauchen Sie nicht einmal ref, weil Sie die Instanz modifizieren und nicht auf sie verweisen.

In diesem Beispiel müssen Sie nicht ref Schlüsselwort, wie Sie Eigenschaft ändern:

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

    static void Method(MyClass instance) 
    { 
     instance.MyProperty = 10;      
    } 

    static void Main(string[] args) 
    { 
     MyClass instance = new MyClass(); 
     Method(instance); 

     Console.WriteLine(instance.MyProperty); 
    } 

Ausgang: 10

Und hier tun Sie ref Stichwort, weil Sie mit Bezug arbeiten und nicht mit Beispiel:

... 

    static void Method(MyClass instance) 
    { 
     // instance variable holds reference to same object but it is different variable 
     instance = new MyClass() { MyProperty = 10 }; 
    } 

    static void Main(string[] args) 
    { 
     MyClass instance = new MyClass(); 
     Method(instance); 

     Console.WriteLine(instance.MyProperty); 
    } 

Ausgang: 0

Es ist das gleiche für Ihr Szenario, Erweiterungsmethoden sind die gleichen wie normale statische Methoden, und wenn Sie ein neues Objekt innerhalb der Methode erstellen, dann verwenden Sie entweder ref Schlüsselwort (es ist nicht möglich für Erweiterungsmethoden) oder dieses Objekt zurückgeben, ansonsten wird der Verweis darauf sein hat verloren.

public static List<T> Method<T>(this List<T> list, Func<T, bool> predicate) 
{ 
    return list.Where(predicate).ToList(); 
} 

List<int> ints = new List<int>(new int[] { 1, 2, 3, 4, 5 }); 
ints = ints.Method(i => i > 2); 

foreach(int item in ints) Console.Write(item + " "); 

Ausgabe:: 3, 4, 5