2010-03-10 77 views
14

在Java世界中,我们有Apache Commons'ToStringBuilder来帮助创建toString()实现。是否有与C#的Java的ToStringBuilder相当的功能?什么是一个好的C#版本功能?

有谁知道C#有一个体面的免费实现吗?有没有更好的选择我不知道?

如果没有免费的实现存在,我想这个问题变得更多的是一个问题“什么会在C#3中成为一个好的ToStringBuilder?”

关闭我的头顶:

  • ,它还可以提供反射和手动的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 ..我正在寻找一个类似于阿帕奇常见的ToStringBuilder的功能,它具有的功能,如多行的格式,不同的样式和反射基础ToString创建。谢谢。

更新2

我已经建立了我自己。见here

+0

也许你应该链接到ToStringBuilder所做的描述:http://commons.apache.org/lang/api/org/apache/commons/lang/builder/ToStringBuilder。html – Powerlord 2010-03-10 14:44:04

+0

@Powerlord,谢谢我已经更新了链接,我猜并不是每个人都像我一样喜欢grokking源代码;-) – chillitom 2010-03-10 14:48:20

+0

快速C#4版本添加如下:http://stackoverflow.com/questions/2417647/is-有一个相当于javas-tostringbuilder-for-c-what-will-a-good-c-ver/4959343#4959343 – chillitom 2011-02-10 15:53:01

回答

13

编辑:OK,你要使用反射,这样你就不必键入属性名称。我认为这将让你你以后:

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

输出:

事{Id:10,Name:“Bob”}

+2

差不多一样好,它有字符串文字,并且不能存活重构 – 2010-03-10 14:49:06

+0

谢谢Dan,这是一个非常好的解决方案。如果我们可以进一步扩展Java版本并使用表达式去除名称字符串,这将是很酷的,这样代码就可以重构。 – chillitom 2010-03-10 15:02:37

+0

@chillitom:我给它敲了一下 - 看看。 – 2010-03-10 15:59:49

1

使用.NET的StringBuilder

请注意,您必须自己提供一个小模板。

E.g:

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

return sb; 
} 

提供这里还挺generic方式。 您可以在.NET创建与System.Reflection命名自己巧妙的解决办法

干杯

+0

谢谢,但我追求的东西完全不同,字符串生成器很好,但需要更多嫁接成一个比Java的Apache Commons ToStringBuilder所做的漂亮的ToString。 – chillitom 2010-03-10 14:41:09

+0

看到它,你可以尝试制作自己的ToStringBuilder方法,它包含一个stringbuilder .. – 2010-03-10 14:42:17

+0

你发布的方法只返回一个字符串。 – 2010-03-10 14:44:54

1

看到这个项目......

http://commonsdotnet.codeplex.com/

+0

感谢mxmissile,我知道某些东西必须存在某处。虽然看起来有点令人失望,但我猜测它的目标是C#版本2及以下版本。它与Java类非常不同,它只是一堆静态调用,并且需要将字段名称作为字符串列表传入,而使用C#3肯定可能更好。 – chillitom 2010-03-10 15:17:24

+0

是的,只是注意到了,我发誓我曾在某处看过这个地方,认为那是地方。将继续寻找,我也可以使用这样的事情。 – mxmissile 2010-03-10 15:24:32

0

我不知道任何现有的项目会做你想做的事情,但实现你使用lambda表达式的例子并不难。

这里的另一个[未经测试/未编译/可能错误]想法使用匿名委托:

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

ToString()超载将被写为一个扩展方法,所以你能在源对象的引用,并会接受Action<T>其中[T]是源对象的类型。然后,ToString()方法将新建一个字符串构建器或某种内部对象,执行从调用者传入的匿名方法,然后将结果包含在任何必需的开始/结束文本中。

要说清楚,我实际上并没有试过这个。我只是觉得它比原始问题中基于lambda的示例更灵活一些。

3

由于它不是免费的,它可能并不完全符合你的要求,但Resharper可以做到这一点。这是一个梦幻般的插件,视觉工作室不仅仅是生成ToString。但它会这样做。把你的光标放在你的班级里,按Alt + Insert并选择格式化成员。有关

+0

+1为了更好的修复技巧! – IAdapter 2011-02-06 21:44:45

3

原来的问题C#3.5,但从那时起,我升级到C#4

我想我会在这里分享我的新版本的情况下,这是有利于他人。它具有此线程中提到的所有功能,并在运行时编译为快速的Stringify方法。

从这里下载:ToStringBuilder

+0

hi chillitom,你的ToStringBuilder看起来很棒,但它似乎不能处理泛型列表,比如List ,它只是在列表中调用ToString()而不枚举,所以你只需要获取列表的全名而不是内容。我试图增强它来处理列表,但我无法绕过使用linq表达式的泛型。你有没有增强它来处理泛型列表?谢谢! – matao 2014-09-16 05:54:50

+0

对不起,我没有,但我会接受一个拉请求。反射API可让您使用泛型类型并创建具体化类型,例如typeof(List <>)。MakeGenericType(typeof(int))=== typeof(列表) – chillitom 2014-09-17 16:08:51

+0

好吧,我想弄明白,当我做我会给你发一个请求。干杯! – matao 2014-09-18 01:30:36

0

ObjectPrinter将与一些自定义的功能为你做这个。文档仍然有点粗糙,但是我们已经在生产中使用了多年,并取得了很好的成果。

相关问题