2009-04-09 15 views
7

Tengo dos métodos que básicamente convierten el texto o la etiqueta de las casillas de verificación subyacentes como cadenas de CSV.
¿Puede refactorizar una funcionalidad común de estos dos métodos?

Estos dos métodos

  • GetSelectedTextAsCsv()
  • GetTagAsCsv()

difieren sólo por el cual propiedad para extraer valor de SelectedCheckBoxes, que es de tipo IList<CheckBox>

public string GetSelectedTextAsCsv() 
    { 
     var buffer = new StringBuilder(); 
     foreach (var cb in SelectedCheckBoxes) 
     { 
      buffer.Append(cb.Text).Append(","); 
     } 
     return DropLastComma(buffer.ToString()); 
    } 

    public string GetTagAsCsv() 
    { 
     var buffer = new StringBuilder(); 
     foreach (var cb in SelectedCheckBoxes) 
     { 
      buffer.Append(cb.Tag).Append(","); 
     } 
     return DropLastComma(buffer.ToString()); 
    } 

Estaba intentando extraer un método que arroja un Func<T, TResult> pero no estoy seguro de cómo puedo lograrlo. Mi pobre intento era como el siguiente, pero no puedo encontrar la manera de extraer la parte de la propiedad, como se muestra en el comentario dentro ConvertToCsv()

public Func<T, string> ConvertToCsv<T>() 
    { 
     return propertyName => 
     { 
      var buffer = new StringBuilder(); 
      foreach (var checkBox in SelectedCheckBoxes) 
      { 
       buffer.Append(
        /* How can you abstract this portion? like following? */ 
        checkBox.propertyName 
       ).Append(","); 
      } 
      return DropLastComma(buffer.ToString()); 
     }; 
    } 

Si estoy en un camino equivocado, ¿podría aconsejarme sobre cómo puedo refactorizar el código para usar un método común?

[ACTUALIZACIÓN 1] Aquí es la combinación de ambas respuestas de Jon Brian y

public string ConvertToCsv<T>(Func<CheckBox, T> getValue) 
    { 
     var stringValues = SelectedCheckBoxes.Select(
      cb => getValue(cb).ToString()).ToArray(); 
     return string.Join(",", stringValues); 
    } 

    public string GetSelectedTextAsCsv() 
    { 
     return ConvertToCsv(cb => cb.Text); 
    } 

    public string GetTagAsCsv() 
    { 
     return ConvertToCsv(cb => cb.Tag); 
    } 

[ACTUALIZACIÓN 2] versión 2

public string GetAsCsv<T>(Func<CheckBox, T> getValue) 
    { 
     return string.Join(",", SelectedCheckBoxes.Select(
      cb => getValue(cb).ToString()).ToArray()); 
    } 

    public string GetSelectedTextAsCsv() 
    { 
     return GetAsCsv(cb => cb.Text); 
    } 

    public string GetTagAsCsv() 
    { 
     return GetAsCsv(cb => 
      cb.Tag == null ? string.Empty : cb.Tag.ToString()); 
    } 

[Actualización 3] hizo el parámetro de GetAsCsv() como un genérico cerrado de CheckBox y cadena

Func<CheckBox, T> a Func<CheckBox, string>.

Eso me permitió hacer GetAsCsv() aún más simple y más legible.

private string GetAsCsv(Func<CheckBox, string> getValue) 
{ 
    return string.Join(",", SelectedCheckBoxes.Select(getValue).ToArray()); 
} 

Respuesta

22
public string GetAsCsv(Func<CheckBox, string> getValue) 
{ 
    var buffer = new StringBuilder(); 
    foreach (var cb in SelectedCheckBoxes) 
    { 
     buffer.Append(getValue(cb)).Append(","); 
    } 
    return DropLastComma(buffer.ToString()); 
} 

continuación:

GetAsCsv(cb => cb.Tag != null ? cb.Tag.ToString() : string.Empty); 
GetAsCsv(cb => cb.Text); 
+0

De hecho estoy utilizando su solución al igual que la de Jon. Es difícil decidir ... – Sung

+0

w00t! Programación funcional :) – Juliet

+0

@Princess: ¿Es un enfoque de programación funcional? Ni siquiera estoy al tanto ... – Sung

0

Dado que las dos funciones son exactamente los mismos, excepto para el comprador, que es donde debe empezar: La parte móvil.

No haber rozado mi C# todavía, pero algo en la línea de:

public string GetCsv(Func<string> getter) 
    { 
     var buffer = new StringBuilder(); 
     foreach (var cb in SelectedCheckBoxes) 
     { 
      buffer.Append(getter()).Append(","); 
     } 
     return DropLastComma(buffer.ToString()); 
    } 

debería funcionar. Además, ¿la variable SelectedCheckBoxes es variable?

+0

Leyó la pregunta incorrectamente, SelectedCheckBoxes es variable, la propiedad que se utiliza en cb es variable. – Samuel

19

que haría uso de string.Join lugar:

string tags = string.Join(",", 
        SelectedCheckBoxes.Select(cb => Convert.ToString(cb.Tag)) 
            .ToArray()); 
string text = string.Join(",", 
        SelectedCheckBoxes.Select(cb => cb.Text).ToArray()); 

Claro, usted podría poner esto en un método, pero probablemente no me molestaría por sólo dos llamadas.

Si quisiera, sin embargo, aquí es cómo se vería el uso de la plantilla de Brian:

public string GetAsCsv(Func<CheckBox, string> getValue) 
{ 
    string[] array = SelectedCheckBoxes.Select(getValue).ToArray(); 
    return string.Join(",", array); 
} 
+0

Muy buena reducción. –

+0

Wow. Ahora eso me permitirá eliminar por completo "DropLastComma()" – Sung

+0

No string.Join ¿espera una cadena []? ¿Cómo funciona esto para Tag, que es un objeto? –

2

Se puede usar un lambda:

public string ConvertToCSV(Func<CheckBox, string> cb_prop) { 
    ... 
    buffer.Append(cb_prop(cb)).Append(","); 
    ... 

} 

ConvertToCSV(c => c.Tag); 
1

que acababa de escribir un método de extensión corta alrededor de IEnumerable cadena que llevó a un separador:

public static string Join(this IEnumerable<string> strings, string separator) 
{ 
    return string.Join(separator, strings.ToArray()); 
} 

entonces usted puede hacer:

var text = SelectedCheckBoxes.Select(cb => cb.Text).Join(", "); 
var tags = SelectedCheckBoxes.Select(cb => (string)cb.Tag).Join(", "); 
Cuestiones relacionadas