2009-04-09 6 views
7

Mam dwie metody, które zasadniczo konwertuje tekst lub znacznik pola wyboru jako ciągi CSV.
Czy można refactor out wspólnej funkcji z tych dwóch metod?

Te dwie metody

  • GetSelectedTextAsCsv()
  • GetTagAsCsv()

różnią się tylko w którym właściwość wyodrębnić wartość od SelectedCheckBoxes, który jest typu 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()); 
    } 

Próbowałem wyodrębnić metodę, która zwraca Func<T, TResult>, ale nie jestem pewien, jak mogę to zrobić. Mój biedny próba była jak poniżej, ale nie mogę dowiedzieć się, jak wyodrębnić część nieruchomości, jak pokazano w komentarzu ciągu 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()); 
     }; 
    } 

Jeśli jestem na złej drodze, to proszę mi doradzić, w jaki sposób mogę refactor powyżej kodu, aby użyć wspólnej metody?

[UPDATE 1] Oto połączenie obu Brian i odpowiedzi Jona

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

[UPDATE 2] wersja 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()); 
    } 

[UPDATE 3] Made parametr GetAsCsv() jako zamknięty generic CheckBox i ciąg

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

To pozwoliło mi uczynić GetAsCsv() jeszcze prostszym i bardziej czytelnym.

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

Odpowiedz

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

Następnie:

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

Używam twojego rozwiązania, a także Jona. Trudno zdecydować ... – Sung

+0

w00t! Programowanie funkcjonalne :) – Juliet

+0

@Princess: Czy jest to podejście do programowania funkcjonalnego? Nie mam pojęcia o tym ... – Sung

0

Ponieważ te dwie funkcje są dokładnie takie same wyjątkiem dla getter, to gdzie należy zacząć: Część ruchoma.

Czy nie czyści mój C# jeszcze, ale coś wzdłuż linii:

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

powinno działać. Czy zmienna jest zmienna SelectedCheckBoxes?

+0

Czytasz pytanie źle, SelectedCheckBoxes jest zmienna, właściwość używana na cb jest zmienna. – Samuel

19

użyję string.Join zamiast:

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

Oczywiście, można umieścić, że do metody, ale prawdopodobnie nie będzie przeszkadzało w ciągu zaledwie dwóch połączeń.

Jeśli chciał jednak, oto jak to będzie wyglądać przy użyciu Briana szablonu:

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

Bardzo ładna redukcja. –

+0

Wow. Teraz to pozwoli mi całkowicie usunąć "DropLastComma()" – Sung

+0

Czy nie string.Join oczekiwać ciąg []? Jak to działa w przypadku tagu, który jest obiektem? –

2

można użyć lambda:

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

} 

ConvertToCSV(c => c.Tag); 
1

chcę tylko napisać metodę krótki przedłużacz wokół IEnumerable ciąg, który wziął separator:

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

następnie można zrobić:

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