Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there an equivalent to Java's ToStringBuilder for C#? What would a good C# version feature?

In the Java world we have Apache Commons' ToStringBuilder to help with creating toString() implementations.

Does anyone know of a decent free implementation for C#? Are there better alternatives I don't know about?

If no free implementation exists than I guess this question becomes more of a question of "What would make a good ToStringBuilder in C# 3?"

Off the top of my head:

  • It could offer both reflection and manual ToString string creation.

  • It would be really cool if it could make use of Expression trees.

Something like this..

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

Which would return:

 "Foo{Id: 1, Name: AName}"
  • It could use System.Reflection.Emit to precompile a ToString delegate.

Any other ideas?

UPDATE

Just to clarify ToStringBuilder is a different creature to StringBuilder.. I'm looking for something akin to the functionality of Apache Common's ToStringBuilder, it has features such as multi-line formatting, different styles and reflection base ToString creation. Thanks.

UPDATE 2

I've built my own. See here.

like image 405
chillitom Avatar asked Mar 10 '10 14:03

chillitom


4 Answers

EDIT: OK, you want to use reflection so you don't have to type property names. I think this will get you what you're after:

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

Example:

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

Behold, the behavior you're after:

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

Output:

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

like image 85
Dan Tao Avatar answered Nov 10 '22 10:11

Dan Tao


The original question concerned C# 3.5 but since then I've upgraded to C# 4.

I thought I'd share my new version here in case it's of benefit to others. It has all of the features mentioned in this thread and compiles at runtime to a fast Stringify method.

Get it here: ToStringBuilder

like image 28
chillitom Avatar answered Nov 10 '22 10:11

chillitom


It might not be exactly what you are after since it is not free, but Resharper will do this. It is a fantastic plugin to visual studio that does a lot more than generate ToString. But it will do that to. put your cursor inside your class, hit alt+insert and choose formating members.

like image 3
Mike Two Avatar answered Nov 10 '22 10:11

Mike Two


Use .NET's StringBuilder.

Note that you'll have to provide a little template yourself.

E.g:

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

return sb;
}

Provided a kinda generic way here. You'll be able to create your own neat solution with the System.Reflection namespace in .NET

Cheers

like image 1
Faizan S. Avatar answered Nov 10 '22 11:11

Faizan S.