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 othe开发者_如何学Gor 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.
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"}
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
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.
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
See this project...
http://commonsdotnet.codeplex.com/
ObjectPrinter will do this for you with a number of customizable features. documentation is still a little rough, but we've been using it in production for years with great results.
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.
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.
精彩评论