是否有与 C# 的 Java 的 ToStringBuilder 等效的工具?一个好的 C# 版本应该具备哪些功能?
-
19-09-2019 - |
题
在 Java 世界中,我们有 Apache Commons' 字符串生成器 帮助创建 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
我已经建立了自己的。看 这里.
解决方案
编辑:好的,您想使用反射,这样就不必键入属性名称。我想这会让你得到你想要的:
// 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、姓名:“鲍勃”}
其他提示
最初的问题涉及 C# 3.5,但从那时起我已经升级到 C# 4。
我想我应该在这里分享我的新版本,以防它对其他人有益。它具有本线程中提到的所有功能,并在运行时编译为快速 Stringify 方法。
在这里获取: 字符串生成器
它可能不完全是您所追求的,因为它不是免费的,但是 雷夏珀 会这样做。它是 Visual Studio 的一个很棒的插件,它的作用不仅仅是生成 ToString。但它会做到这一点。将光标放在类中,按 alt+insert 并选择格式化成员。
使用.NET 字符串生成器.
请注意,您必须自己提供一个小模板。
例如:
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 中的命名空间
干杯
看到这个项目...
对象打印机 将通过许多可定制的功能为您做到这一点。文档仍然有点粗糙,但我们已经在生产中使用它多年并取得了很好的结果。
我认为您正在使用表达式。前几天晚上我读到了这篇文章: 使用表达式树获取有关对象、类型和成员的信息
我敢打赌,您可以将这些技术与 Dan 在该线程上发布的代码结合起来,以获得您想要的结果。
我不知道有任何现有项目可以满足您的要求,但使用 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 的示例更灵活一些。