Удалить дубликаты из этого фрагмента кода - PullRequest
2 голосов
/ 28 октября 2011

Нужны советы по удалению дублирования из этого фрагмента:

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

РЕДАКТИРОВАТЬ: Это упрощенный контекст, может быть больше списков соединений, как эти

Ответы [ 3 ]

3 голосов
/ 28 октября 2011

Я не думаю, что удаление того, что вы называете «дублированием», необходимо.У вас нет двух вхождений идентичного кода, но есть два вхождения похожего кода.Это обычное дело, и не о чем беспокоиться.

2 голосов
/ 28 октября 2011

Как насчет перевернуть проблему с ног на голову?Вместо того, чтобы функция понимала формат DataRow для каждого объекта, пусть каждый объект понимает формат DataRow.Если вы не используете object.ToString() для чего-либо, вы можете заставить ConfigurationItem и OptionalItem реализовать 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 format":

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();
}
2 голосов
/ 28 октября 2011

Я согласен, что не так много дублирования, но, возможно, этот «буквальный перевод» в расширения 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);
}

В качестве альтернативы, вы могли бы написать это несколько более разборчиво (/ эффективно?) Без строителей строк:

Извлечение лямбды сделало строки короче:

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 вам нужно дополнительно .ToArray() вызвать второй параметр для string.Join

...