2010-02-24 12 views
24

Quiero ser capaz de escribir métodos de extensión por lo que puedo decir:¿Cómo puedo obtener un método de extensión para cambiar el objeto original?

lines.ForceSpaceGroupsToBeTabs(); 

en lugar de:

lines = lines.ForceSpaceGroupsToBeTabs(); 

Sin embargo, el siguiente código actualmente da salida:

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

en lugar de:

Tone 
TTtwo 

¿Qué tengo que cambiar en el siguiente código para que produzca:

Tone 
TTtwo 

(tenga en cuenta que para la visibilidad, . = 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; 
     } 
    } 
} 

Respuesta

36

Hay que modificar el contenido del List<string> pasado al método de extensión, no la variable que contiene la referencia a la lista:

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

De hecho. No puede cambiar el objeto referenciado "extendido", pero puede cambiar los contenidos –

15

Debería cambiar el contenido de la lista original; solo reasignar el parámetro para que tenga un valor diferente no lo va a hacer. Algo como esto:

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"); 
    } 
} 

Vale la pena señalar que esta tiene nada que ver con los métodos de extensión. Imagine que acaba de llamar:

Helpers.ForceSpaceGroupsToBeTabs(lines); 

... porque eso es lo que el código se traduce efectivamente. No hay nada de especial en el hecho de que es un método de extensión; si cambias el código para que funcione el método estático "normal", también funcionará como un método de extensión. Como se indicó en los comentarios, una cosa que no se puede hacer con con un método de extensión es convertir el primer parámetro en un parámetro ref.

(EDIT:.. Me di cuenta que es exactamente el mismo código que DTB publicada, aunque llegamos allí de forma independiente me quedo con esta respuesta de todos modos, ya que tiene más de código)

+1

, no es exactamente el mismo código, tiene spaceGroup ("T"), ¿estaba pensando en otra cosa o fue solo un error tipográfico (no lo hace? compilar) –

+0

@Jon: La diferencia es que con Helpers.ForceSpaceGroupsToBeTabs podría cambiar el parámetro para que sea un parámetro "ref", en cuyo caso su código * * tendría el efecto deseado. Sin embargo, con los métodos de extensión, no se puede hacer el parámetro ref ... – BFree

+0

@BFree: eso es cierto - se editará. –

10

Si se trata de un tipo de referencia , tendrías que cambiar sus contenidos. Si es un tipo de valor que está pasando, no tiene suerte. La misma existencia de los métodos de extensión se pone en marcha para apoyar paradigmas funcionales en C#, y esos paradigmas funcionales, por su propia esencia, tienden a la inmutabilidad de los tipos, de ahí la incapacidad de cambiar el valor del cual se llama el método de extensión.

En otras palabras, mientras que podría hacerlo, puede no estar en consonancia con el "espíritu" de la programación funcional.

+3

Creo que la segunda parte de esta respuesta es engañosa. El caso de uso abrumador para los métodos de extensión está en las interfaces, que son tipos de referencia, y en esos casos no hay un límite especial para la mutación: las capacidades son idénticas a los métodos ordinarios, en que 'a.SomeMethod();' no puede hacer 'a 'se refiere a algo más, pero puede cambiar el objeto al que se refiere. –

Cuestiones relacionadas