2010-02-24 2 views
24

Ich mag Erweiterungsmethoden schreiben können so dass ich sagen kann:Wie kann ich eine Erweiterungsmethode zum Ändern des ursprünglichen Objekts erhalten?

lines.ForceSpaceGroupsToBeTabs(); 

statt:

lines = lines.ForceSpaceGroupsToBeTabs(); 

Allerdings gibt den folgenden Code zur Zeit:

....one 
........two 

anstelle von:

Tone 
TTtwo 

Was muss ich im folgenden Code ändern, um es Ausgabe zu machen:

Tone 
TTtwo 

(beachten, dass für die Sichtbarkeit, . = space, T = \t):

using System; 
using System.Collections.Generic; 

namespace TestExtended82343 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<string> lines = new List<string>(); 
      lines.Add("....one"); 
      lines.Add("........two"); 

      lines.ForceSpaceGroupsToBeTabs(); 

      lines.ForEach(l => Console.WriteLine(l)); 
      Console.ReadLine(); 
     } 
    } 

    public static class Helpers 
    { 
     public static void ForceSpaceGroupsToBeTabs(this List<string> originalLines) 
     { 
      string spaceGroup = new String('.', 4); 
      List<string> lines = new List<string>(); 
      foreach (var originalLine in originalLines) 
      { 
       lines.Add(originalLine.Replace(spaceGroup, "T")); 
      } 
      originalLines = lines; 
     } 
    } 
} 

Antwort

36

Sie haben den Inhalt ändern der List<string> an die Erweiterungsmethode übergeben, nicht die Variable, die den Verweis auf die Liste enthält:

public static void ForceSpaceGroupsToBeTabs(this List<string> lines) 
{ 
    string spaceGroup = new String('.', 4); 
    for (int i = 0; i < lines.Count; i++) 
    { 
     lines[i] = lines[i].Replace(spaceGroup, "T"); 
    } 
} 
+0

In der Tat. Sie können das "erweiterte" referenzierte Objekt nicht wechseln, aber Sie können seinen Inhalt ändern –

15

Sie müssten die Inhalt der ursprünglichen Liste ändern - nur die Neuzuweisung des Parameters, um einen anderen Wert zu haben, wird es nicht tun. Etwas wie folgt aus:

public static void ForceSpaceGroupsToBeTabs(this List<string> lines) 
{ 
    string spaceGroup = new String('.', 4); 
    for (int i = 0; i < lines.Count; i++) 
    { 
     lines[i] = lines[i].Replace(spaceGroup, "T"); 
    } 
} 

Es ist erwähnenswert, dass diese nichts mit Erweiterungsmethoden zu tun hat. Stellen Sie sich vor, Sie hätten gerade angerufen:

Helpers.ForceSpaceGroupsToBeTabs(lines); 

... weil das ist, was der Code effektiv übersetzt wird. Es ist nichts besonderes an der Tatsache, dass es eine Erweiterungsmethode ist; Wenn Sie den Code ändern, so dass die "normale" statische Methode funktioniert, dann wird es auch als eine Erweiterungsmethode funktionieren. Wie in den Kommentaren erwähnt, eine Sache, die Sie nicht können machen mit einer Erweiterungsmethode ist der erste Parameter ein ref Parameter.

(EDIT:.. Ich weiß, das genau die gleiche Code, geschrieben DTB, obwohl wir dort unabhängig kam ich halte diese Antwort sowieso, da es mehr als Code bekam ist)

+1

es ist nicht der exakt gleiche Code, Sie haben spaceGroup ("T"), haben Sie an etwas anderes gedacht oder war das nur ein Tippfehler (es tut nicht Kompilieren) –

+0

@Jon: Der Unterschied ist, dass mit Helpers.ForceSpaceGroupsToBeTabs er könnte den Parameter ändern, um ein "ref" -Parameter zu sein, in diesem Fall würde sein existierender Code * den gewünschten Effekt haben. Mit Erweiterungs-Methoden können Sie jedoch nicht den Parameter ref ... – BFree

+0

@BFree: Das stimmt - wird bearbeiten. –

10

Wenn es ein Referenztyp ist , müssten Sie den Inhalt ändern. Wenn es sich um einen Werttyp handelt, den Sie gerade durchgehen, haben Sie kein Glück. Die bloße Existenz von Erweiterungsmethoden wird eingeführt, um funktionale Paradigmen in C# zu unterstützen, und diese funktionalen Paradigmen tendieren von Natur aus zur Unveränderlichkeit von Typen, daher die Unfähigkeit, den Wert zu ändern, von dem die Erweiterungsmethode aufgerufen wird.

Mit anderen Worten, während Sie könnte es tun, kann es nicht im Einklang mit dem "Geist" der funktionalen Programmierung.

+3

Ich denke, der zweite Teil dieser Antwort ist irreführend. Der überwältigende Anwendungsfall für Erweiterungsmethoden ist Schnittstellen, die Referenztypen sind, und in diesen Fällen gibt es keine spezielle Grenze für Mutation: die Fähigkeiten sind identisch mit gewöhnlichen Methoden, in denen 'a.SomeMethod();' 'a nicht machen kann 'beziehen sich auf etwas anderes, können aber das Objekt, auf das es verweist, ändern. –

Verwandte Themen