你能从这两个方法中重构出一个共同的功能吗?

7
我有两种方法,基本上可以将底层复选框的文本或标签转换为CSV字符串。
这两种方法如下:
  • GetSelectedTextAsCsv()
  • GetTagAsCsv()
它们唯一不同的是从SelectedCheckBoxes中提取值的属性,这个属性的类型是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());
    }

我试图提取一个返回Func<T, TResult>的方法,但不确定如何实现。 我的尝试如下,但我无法弄清楚如何提取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());
        };
    }

如果我走错了路,请您告诉我如何重构上面的代码以使用公共方法?
[更新1] 这是Brian和Jon答案的结合。
    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);
    }

[更新2] 版本 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());
    }

[更新3]GetAsCsv()的参数更改为CheckBox和string的封闭泛型。

Func<CheckBox, T> 更改为 Func<CheckBox, string>

这使得GetAsCsv()变得更简单、更易读。

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

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

那么:

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

w00t!函数式编程 :) - Juliet
你确定要使用 ?? 吗? - Daniel LeCheminant
@Daniel L:不,?? 会返回标签对象,而不是字符串。 - Brian Genisio
+标记为答案:Jon的回答很好,但必须尊重回答了原始问题的人。 - dance2die

19

我会使用string.Join代替:

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

当然,你可以把那个放到一个方法中,但是对于只有两个调用来说,我可能不会费心去做。

如果你想要的话,这就是使用Brian的模板所看起来的样子:

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

哇,现在我可以完全删除“DropLastComma()”了。 - dance2die
除非我完全错了,否则我认为你的标签方法甚至无法编译 :-/ - Daniel LeCheminant
@Sung:好的...我想这很有趣/可悲,当我从Jon的代码中得到编译器错误时,我会认为一定是我做错了什么! - Daniel LeCheminant
@Jon:如果标签为空,那么这不会抛出一个NullReferenceException吗? - Daniel LeCheminant
@Dan Goldstein:我非常喜欢“GetAsCsv()”,我可能会将其放入我的代码库中的通用“String”库中。 - dance2die
显示剩余3条评论

2
你可以使用lambda函数:
public string ConvertToCSV(Func<CheckBox, string> cb_prop) {
    ...
    buffer.Append(cb_prop(cb)).Append(",");
    ...

}

ConvertToCSV(c => c.Tag);

1

我只需要编写一个围绕IEnumerable string的短扩展方法,该方法使用分隔符:

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

然后你可以做:

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

0

由于这两个函数除了getter之外完全相同,因此您应该从移动部分开始:

我还没有熟悉C#,但大致上是这样的:

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

应该可以工作。另外,将SelectedCheckBoxes变量化?


你读错了问题,SelectedCheckBoxes是变量,它在cb上使用的属性也是变量。 - Samuel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接