17

在 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

我已经建立了自己的。见这里

4

8 回答 8

13

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

// 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”}

于 2010-03-10T14:44:00.090 回答
4

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

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

在这里获取:ToStringBuilder

于 2011-02-10T15:52:27.030 回答
3

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

于 2010-03-10T18:58:43.913 回答
1

使用 .NET 的StringBuilder

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

例如:

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

return sb;
}

在这里提供了一种generic方式。System.Reflection您将能够使用.NET中的命名空间创建自己的简洁解决方案

干杯

于 2010-03-10T14:34:52.917 回答
1

看到这个项目...

http://commonsdotnet.codeplex.com/

于 2010-03-10T15:05:59.767 回答
1

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

于 2013-12-27T00:22:48.600 回答
0

我认为您正在使用表达式。前几天晚上我读了这篇文章:使用表达式树获取有关对象、类型和成员的信息

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

于 2010-03-10T15:41:45.450 回答
0

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

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

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

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

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

于 2010-03-10T15:47:51.897 回答