I have two methods that basically converts underlying checkboxes' text or tag as CSV strings.
These two methods
- GetSelectedTextAsCsv()
- GetTagAsCsv()
differ only by which property to extract value from SelectedCheckBoxes
, which is of type 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());
}
I was trying to extract a method that returns a Func<T, TResult>
but not sure how I can pull that off.
My poor attempt was like the following but I cannot figure out how to extract the property portion as shown in the comment within 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());
};
}
If I am on a wrong track, would you please advise me on how I can refactor above code to use a common method?
[UPDATE 1] Here is the combination of both Brian and Jon's answers
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] version 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 the parameter of GetAsCsv()
as a closed generic of CheckBox and string
Func<CheckBox, T>
toFunc<CheckBox, string>
.
That allowed me to make GetAsCsv()
even simpler and more readable.
private string GetAsCsv(Func<CheckBox, string> getValue)
{
return string.Join(",", SelectedCheckBoxes.Select(getValue).ToArray());
}