【问题标题】:Can you refactor out a common functionality from these two methods?你能从这两种方法中重构出一个共同的功能吗?
【发布时间】:2009-04-09 18:55:25
【问题描述】:

我有两种方法可以基本上将底层复选框的文本或标记转换为 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());
    }

[UPDATE 3]GetAsCsv()的参数设为CheckBox和字符串的封闭泛型

Func&lt;CheckBox, T&gt;Func&lt;CheckBox, string&gt;

这让我可以让GetAsCsv() 变得更简单、更易读。

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

【问题讨论】:

    标签: c# .net refactoring csv


    【解决方案1】:
    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);
    

    【讨论】:

    • 哇!函数式编程:)
    • 您确定要使用 ??
    • @Daniel L:不,??将返回选项卡 ojbect,而不是字符串。
    • +标记为答案:Jon 的回答很棒,但必须向回答了原始问题的人表示敬意。
    【解决方案2】:

    我会改用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()”
    • 不是 string.Join 需要一个字符串 [] 吗?这对作为对象的 Tag 有何作用?
    • ...除非我完全遗漏了什么,否则我认为您的标签方法甚至不会编译:-/
    • @Danie L:你是对的。我不得不稍微修改一下源代码。我的解决方案实际上是 Jon 和 Brian 的答案的结合
    • @Sung: 好吧...我想这很有趣/可悲的是,当我从 Jon 的代码中得到编译器错误时,我认为我一定做错了什么!
    【解决方案3】:

    你可以使用 lambda:

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

    【讨论】:

      【解决方案4】:

      我只是在 IEnumerable 字符串周围写了一个简短的扩展方法,它带有一个分隔符:

      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(", ");
      

      【讨论】:

        【解决方案5】:

        由于这两个函数完全相同除了对于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 上使用的属性是可变的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-26
        • 1970-01-01
        • 1970-01-01
        • 2020-02-07
        • 1970-01-01
        • 2011-01-10
        相关资源
        最近更新 更多