tags:

views:

281

answers:

6

In the Java world we have Apache Commons' ToStringBuilder to help with creating toString() implementations. ( http://commons.apache.org/lang/api/org/apache/commons/lang/builder/ToStringBuilder.html )

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.

+3  A: 

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

Shaharyar
thanks but I'm after something quite different, string builder is good but requires much more graft to make a pretty ToString than Java's Apache Commons ToStringBuilder does.
chillitom
saw it, you could try making your own ToStringBuilder method that envelops a stringbuilder..
Shaharyar
@Shaharyar: The method you posted just returns a string.
Dan Tao
@Dan, thanks for pointing that out!
Shaharyar
+10  A: 

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"}

Dan Tao
not nearly as good, this has string literals in it and won't survive refactoring
Ben Voigt
Thanks Dan that's a nice tight solution. Would be cool if we could expand on the Java version further and use expressions to get rid of the name string, that way the code would be refactor proof.
chillitom
@chillitom: I gave it a whack--take a look.
Dan Tao
Sweet! I was just doing something similar myself, this is a tidier than what I have so far.
chillitom
+1  A: 

See this project...

http://commonsdotnet.codeplex.com/

mxmissile
thanks mxmissile, I knew something had to exist somewhere. It's a bit disappointing though, after looking at the source I'm guessing this targets C# versions 2 and below. It is very different from the Java class, it's just a bunch of static calls and requires the field names to be passed in as a list of strings, something much nicer is surely possible with C# 3.
chillitom
yea, just noticed that, I swear I have seen this somewhere, thought that was the place. Will keep looking, I could use something like this also.
mxmissile
A: 

I think that you are on to something with using Expressions. I read this article just the other night: Getting Information About Objects, Types, and Members with Expression Trees

I bet that you could combine those techniques with the code that Dan posted on this thread to get what you are after.

JMarsch
A: 

I don't know of any existing projects that would do what you want, but it wouldn't be that hard to implement the example you gave using lambdas.

Here's another [untested/uncompiled/possibly faulty] idea using anonymous delegates:

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

This ToString() overload would be written as an extension method, so you get a reference to the source object, and would accept an Action<T> where [T] is the type of source object. The ToString() method would then new up a string builder or internal object of some sort, execute the anonymous method passed in from the caller, and then wrap the result in any opening/closing text that is necessary.

To be clear, I haven't actually tried this. I just think its a little more flexible than the lambda-based example in the original question.

Seth Petry-Johnson
A: 

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.

Mike Two