Есть ли эквивалент Java ToStringBuilder для С#? Какая была бы хорошая версия С#?

В мире Java у нас есть Apache Commons ToStringBuilder, чтобы помочь в создании реализаций toString().

Кто-нибудь знает о достойной бесплатной реализации для С#? Есть ли лучшие альтернативы, о которых я не знаю?

Если никакой свободной реализации не существует, я полагаю, что этот вопрос становится скорее вопросом "Что сделало бы хороший ToStringBuilder в С# 3?"

Сверху моей головы:

  • Он может предлагать как отражение, так и ручное создание строки в ToString.

  • Было бы здорово, если бы он мог использовать деревья выражений.

Что-то вроде этого..

 public override string ToString()
   {
      return new ToStringBuilder<Foo>(this)
         .Append(t => t.Id)
         .Append(t => t.Name)
         .ToString();
   }

Что будет возвращено:

 "Foo{Id: 1, Name: AName}"
  • Он может использовать System.Reflection.Emit для прекомпиляции делегата ToString.

Любые другие идеи?

UPDATE

Просто, чтобы уточнить, ToStringBuilder - это другое существо для StringBuilder. Я ищу что-то похожее на функциональность Apache Common ToStringBuilder, он имеет такие функции, как многострочное форматирование, различные стили и базовое представление ToString. Спасибо.

ОБНОВЛЕНИЕ 2

Я построил свой собственный. См. here.

Ответы

Ответ 1

EDIT: ОК, вы хотите использовать отражение, чтобы не вводить имена свойств. Я думаю, что это даст вам то, что вам нужно:

// forgive the mangled code; I hate horizontal scrolling
public sealed class ToStringBuilder<T> {
    private T _obj;
    private Type _objType;
    private StringBuilder _innerSb;

    public ToStringBuilder(T obj) {
        _obj = obj;
        _objType = obj.GetType();
        _innerSb = new StringBuilder();
    }

    public ToStringBuilder<T> Append<TProperty>
    (Expression<Func<T, TProperty>> expression) {

        string propertyName;
        if (!TryGetPropertyName(expression, out propertyName))
            throw new ArgumentException(
                "Expression must be a simple property expression."
            );

        Func<T, TProperty> func = expression.Compile();

        if (_innerSb.Length < 1)
            _innerSb.Append(
                propertyName + ": " + func(_obj).ToString()
            );
        else
            _innerSb.Append(
                ", " + propertyName + ": " + func(_obj).ToString()
            );

        return this;
    }

    private static bool TryGetPropertyName<TProperty>
    (Expression<Func<T, TProperty>> expression, out string propertyName) {

        propertyName = default(string);

        var propertyExpression = expression.Body as MemberExpression;
        if (propertyExpression == null)
            return false;

        propertyName = propertyExpression.Member.Name;
        return true;
    }

    public override string ToString() {
        return _objType.Name + "{" + _innerSb.ToString() + "}";
    }
}

Пример:

// from within some class with an Id and Name property
public override string ToString() {
    return new ToStringBuilder<SomeClass>(this)
        .Append(x => x.Id)
        .Append(x => x.Name)
        .ToString();
}

Вот, поведение, которое вы после:

class Thing {
    public int Id { get; set; }
    public string Name { get; set; }

    public override string ToString() {
        return new ToStringBuilder<Thing>(this)
            .Append(t => t.Id)
            .Append(t => t.Name)
            .ToString()
    }
}

void Main() {
    var t = new Thing { Id = 10, Name = "Bob" };
    Console.WriteLine(t.ToString());
}

Выход:

Thing {Id: 10, Name: "Bob" }

Ответ 2

Возможно, это не совсем то, что вам нужно, поскольку это не бесплатно, но Resharper сделает это. Это фантастический плагин для визуальной студии, который делает намного больше, чем создание ToString. Но он это сделает. поместите курсор в свой класс, нажмите alt + insert и выберите элементы формирования.

Ответ 3

Оригинальный вопрос касался С# 3.5, но с тех пор я обновился до С# 4.

Я думал, что поделюсь своей новой версией здесь, если это принесет пользу другим. Он имеет все функции, упомянутые в этом потоке, и компилирует во время выполнения быстрый метод Stringify.

Получите его здесь: ToStringBuilder

Ответ 4

Используйте .NET StringBuilder.

Обратите внимание, что вам нужно будет предоставить небольшой шаблон самостоятельно.

Например:

public StringBuilder ToStringBuilder<T>(T type) where T : IYourInterface
{
StringBuilder sb = new StringBuilder();
sb.append(type.key);
// more appends

return sb;
}

Предоставлено здесь generic. Вы сможете создать собственное опрятное решение с пространством имен System.Reflection в .NET

Приветствия

Ответ 6

Я думаю, что вы используете что-то с использованием выражений. Я прочитал эту статью совсем недавно: Получение информации об объектах, типах и членах с деревьями выражений

Готов поспорить, что вы могли бы объединить эти методы с кодом, который Дэн опубликовал в этом потоке, чтобы получить то, что вам нужно.

Ответ 7

Я не знаю каких-либо существующих проектов, которые будут делать то, что вы хотите, но было бы не так сложно реализовать пример, который вы дали с помощью lambdas.

Здесь другая [непроверенная/некомпилированная/возможно ошибочная] идея с использованием анонимных делегатов:

public override string ToString() {
    return this.ToString(x => {
        x.Append(t => t.Id);
        x.Append(t => t.Name);
    });
}

Эта перегрузка ToString() будет записана как метод расширения, поэтому вы получите ссылку на исходный объект и будете принимать Action<T>, где [T] - тип исходного объекта. Метод ToString() затем должен был бы создать строковый построитель или внутренний объект какого-либо типа, выполнить анонимный метод, переданный от вызывающего, и затем обернуть результат любым необходимым для открытия/закрытия текста.

Чтобы быть ясным, я на самом деле этого не делал. Я просто считаю его немного более гибким, чем пример на основе лямбда в исходном вопросе.

Ответ 8

ObjectPrinter сделает это для вас с рядом настраиваемых функций. документация по-прежнему немного грубо, но мы используем ее в производстве в течение многих лет с отличными результатами.