【问题标题】:Is there an equivalent to Java's ToStringBuilder for C#? What would a good C# version feature?是否有与 Java 的 C# 的 ToStringBuilder 等价物?什么是好的 C# 版本功能?
【发布时间】:2011-01-25 22:26:48
【问题描述】:

在 Java 世界中,我们有 Apache Commons 的 ToStringBuilder 来帮助创建 toString() 实现。

有人知道 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 委托。

还有其他想法吗?

更新

只是为了澄清 ToStringBuilder 与 StringBuilder 不同。我正在寻找类似于 Apache Common 的 ToStringBuilder 功能的东西,它具有多行格式、不同样式和反射基础 ToString 创建等功能。谢谢。

更新 2

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

【问题讨论】:

标签: c# java reflection apache-commons tostring


【解决方案1】:

ObjectPrinter 将为您提供许多可自定义的功能。文档仍然有些粗糙,但我们多年来一直在生产中使用它并取得了很好的效果。

【讨论】:

    【解决方案2】:

    最初的问题涉及 C# 3.5,但从那以后我升级到了 C# 4。

    我想我会在这里分享我的新版本,以防它对其他人有所帮助。它具有该线程中提到的所有功能,并在运行时编译为快速的 Stringify 方法。

    在这里获取:ToStringBuilder

    【讨论】:

    • 嗨 chilitom,您的 ToStringBuilder 看起来非常棒,但它似乎无法处理通用列表,例如 List,它只是在列表上调用 ToString() 而不枚举,因此您只需获取列表的全名而不是内容。我试图增强它来处理列表,但我无法理解使用带有 linq 表达式的泛型。你有没有增强它来处理通用列表?谢谢!
    • 对不起,我没有,但我会接受拉取请求。反射 API 允许您采用泛型类型并创建具体类型,例如typeof(List).MakeGenericType(typeof(int)) === typeof(List)
    • 好的,我正在努力解决,当我这样做时,我会向您发送请求。干杯!
    • 现在与通用列表完美配合,下一步是弄清楚如何让 git 工作,以便我可以向您发送拉取请求。可能需要一段时间...代码在这里:stackoverflow.com/a/25885391/115734
    • 出色的工作!如果搞清楚 git 的工作量太大,那么 Github 会让你直接在网站上编辑文件,这会创建一个 fork 和分支,然后你可以选择提出 pull request。
    【解决方案3】:

    它可能不是你想要的,因为它不是免费的,但Resharper 会这样做。它是 Visual Studio 的一个很棒的插件,它的功能远不止生成 ToString。但它会这样做。将光标放在班级内,按 alt+insert 并选择格式化成员。

    【讨论】:

      【解决方案4】:

      编辑:好的,您想使用反射,因此您不必键入属性名称。我认为这会让你得到你所追求的:

      // 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,名称:“Bob”}

      【讨论】:

      • 不太好,其中包含字符串文字,无法在重构中幸存
      • 感谢 Dan,这是一个很好的紧凑解决方案。如果我们可以进一步扩展 Java 版本并使用表达式来摆脱名称字符串会很酷,这样代码将是重构证明。
      • @chillitom:我试了一下——看看。
      • 甜蜜!我自己只是在做类似的事情,这比我目前所做的要整洁。
      【解决方案5】:

      我不知道有任何现有项目可以满足您的需求,但是使用 lambda 实现您给出的示例并不难。

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

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

      ToString() 重载将被编写为扩展方法,因此您将获得对源对象的引用,并接受Action&lt;T&gt;,其中[T] 是源对象的类型。然后 ToString() 方法将新建一个字符串构建器或某种内部对象,执行从调用者传入的匿名方法,然后将结果包装在任何必要的打开/关闭文本中。

      需要说明的是,我实际上并没有尝试过这个。我只是认为它比原始问题中基于 lambda 的示例更灵活。

      【讨论】:

        【解决方案6】:

        我认为您对使用表达式有所了解。前几天晚上我读了这篇文章:Getting Information About Objects, Types, and Members with Expression Trees

        我敢打赌,您可以将这些技术与 Dan 在此线程上发布的代码结合起来,以获得您所追求的目标。

        【讨论】:

          【解决方案7】:

          查看这个项目...

          http://commonsdotnet.codeplex.com/

          【讨论】:

          • 感谢 mxmissile,我知道某处必须存在某些东西。不过,这有点令人失望,在查看了源代码之后,我猜这针对的是 C# 版本 2 及以下版本。它与 Java 类非常不同,它只是一堆静态调用,并且需要将字段名称作为字符串列表传入,使用 C# 3 肯定会更好。
          • 是的,刚刚注意到,我发誓我在某个地方看到过这个,还以为是那个地方。会继续寻找,我也可以使用这样的东西。
          【解决方案8】:

          使用 .NET 的 StringBuilder

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

          例如:

          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 命名空间创建自己的简洁解决方案

          干杯

          【讨论】:

          • 谢谢,但我追求的是完全不同的东西,字符串生成器很好,但比 Java 的 Apache Commons ToStringBuilder 需要更多的移植来制作漂亮的 ToString。
          • 看到了,你可以尝试制作你自己的 ToStringBuilder 方法来封装一个 stringbuilder..
          • 你发布的方法只是返回一个字符串。
          猜你喜欢
          • 2011-10-13
          • 1970-01-01
          • 1970-01-01
          • 2017-12-18
          • 2011-01-10
          • 2016-07-26
          • 2010-12-07
          • 2010-11-22
          相关资源
          最近更新 更多