【问题标题】:Remove duplication from this snippet of code从此代码片段中删除重复项
【发布时间】:2011-10-28 12:24:11
【问题描述】:

寻求从这个 sn-p 中删除重复的建议:

foreach (Car car in carList) {
    DataRow row = NewRow();

    StringBuilder sbConfigurations = new StringBuilder();    
    foreach (ConfigurationItem configurationItem in car.Configurations)
        sbConfigurations.AppendFormat("{0}: {1}\n", configurationItem.Name, configurationItem.Value);

    row["configurations"] = sbConfigurations;


    StringBuilder sbOptionals = new StringBuilder();
    foreach (OptionalItem optionalItem in car.Optionals) 
        sbOptionals.AppendFormat("{0}, ", optionalItem.Name);

    row["optionals"] = sbOptionals;

    Rows.Add(row);
}

编辑:这是一个简化的上下文,可能会有更多这样的列表连接

【问题讨论】:

  • 我正在考虑使用带有索引名称的数组,但后来我看到您正在调用car.Optionals。您可以通过使用反射来做到这一点,但这并不能使它变得更好。
  • Configurations 和 Optionals 是否派生自一个公共基类?如果不是,那么显着的简化可能会涉及到反思。如果您要经常这样做,您也许可以证明编写 obj.FormattedOutput(" {Name}: {Value}\n") 之类的函数的努力是合理的

标签: c# coding-style refactoring duplicates


【解决方案1】:

我真的不认为删除您所说的“重复”是必要的。您没有出现两次相同的代码,而是出现两次相似的代码。这很常见,无需担心。

【讨论】:

  • 这是一点,但我仍然认为我可以实现一些东西来抽象行列内的插入 os 列表。
  • @arkilus :是的,你可以,但我不确定在这种简单的情况下是否有意义,会在一分钟内发布解决方案
  • 在我的示例中只有 1 个“重复”,如果我必须添加更多这样的列怎么办?
【解决方案2】:

我同意没有太多重复,但也许这种“直译”到 Linq 扩展 是您要查找的内容(在浏览器中输入,因此尚未测试):

foreach (Car car in carList) {
    DataRow row = NewRow();

    row["configurations"] = car.Configurations.Aggregate(new StringBuilder(), (a,i) => a.AppendFormat("{0}: {1}\n", i.Name, i.Value));
    row["optionals"] = car.Optionals.Aggregate(new StringBuilder(), (a,i) => a.AppendFormat("{0}, ", i.Name));

    Rows.Add(row);
}

或者,您可以在没有字符串生成器的情况下将其写得更清晰(/高效?):

提取 lambda 使行更短:

Func<Car, string> nameValue = car => string.Format("{0}: {1}\n", car.Name, car.Value);

foreach (var car in carList) {
    var row = new Dictionary<string, string>();

    row["configurations"] = string.Join("\n", car.Configurations.Select(nameValue));
    row["optionals"]      = string.Join(", ", car.Optionals.Select(i => i.Name));

    list.Add(row);
}

注意在 C# 4.0 之前,您需要对 string.Join 的第二个参数进行额外的 .ToArray() 调用

【讨论】:

  • 刚刚学习了一个新的c#特性:P,虽然我认为同一行中有太多的函数调用,我也在寻找干净的代码。
  • 呵呵。确实改进了一点 - 解决了“排长队”的投诉。
【解决方案3】:

把问题颠倒过来怎么样。不要让函数理解每个对象的DataRow 格式,而是让每个对象理解DataRow 格式。如果你不使用object.ToString() 做任何事情,你可以让ConfigurationItemOptionalItem 实现object.ToString()

class ConfigurationItem
{
    public string override ToString()
    {
        return string.Format("{0}: {1}\n", Name, Value);
    }
}

class OptionalItem
{
    public string override ToString()
    {
        return string.Format("{0}, ", Name);
    }
}

现在您可以对所有类型的对象使用单个循环:

string BuildDataRowString(IEnumerable collection)
{
    var sb = new StringBuilder();
    foreach (var o in collection) sb.Append(o.ToString());
    return sb.ToString();
}

row["configurations"] = car.Configurations.BuildDataRowString();
row["optionals"] = car.Optionals.BuildDataRowString();

如果您需要object.ToString()用于其他用途,您可以为“DataRow格式”添加自定义格式:

class ConfigurationItem : IFormattable
{
    public string override ToString(string format, IFormatProvider formatProvider)
    {
        if (format == "D") {
            return string.Format(formatProvider, "{0}: {1}\n", Name, Value);
        }
        return this.ToString(); // otherwise format as default
    }
}

class OptionalItem : IFormattable
{
    public string override ToString(string format, IFormatProvider formatProvider)
    {
        if (format == "D") {
            return string.Format(formatProvider, "{0}, ", Name);
        }
        return this.ToString(); // otherwise format as default
    }
}

string BuildDataRowString(this IEnumerable e, string format)
{
    StringBuilder sb = new StringBuilder();
    foreach (var o in e) sb.AppendFormat("{0:D}", o);
    return sb.ToString();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-20
    • 2011-06-04
    • 2021-09-11
    • 1970-01-01
    • 1970-01-01
    • 2021-04-08
    • 1970-01-01
    相关资源
    最近更新 更多