C# Interactive 中对象的自定义打印
Custom print of object in C# Interactive
考虑这个 MCVE class:
public class Foo<T>
{
private readonly T value;
public Foo(T value)
{
this.value = value;
}
}
当我在 C# Interactive 中评估和打印这样一个对象时,它看起来像这样:
> new Foo<string>("bar")
Foo<string> { }
这没用。我希望它看起来像这样:
Foo<string> { "bar" }
我该怎么做?
我试过像这样覆盖 ToString
:
public override string ToString()
{
return $"Foo{typeof(T)} {{ {value} }}";
}
这不是我想要的结果:
> new Foo<string>("bar")
[Foo<System.String> { bar }]
此输出至少存在三个问题:
- 该值不在引号中。我希望它是
"bar"
而不是 bar
.
- 类型参数显示为
System.String
而不是 string
。
- 整个值都用方括号括起来。这是我最不关心的。
有没有办法让 C# 交互式显示具有自定义格式的对象?
我知道我可以将 public 属性 添加到 class 以显示值,但由于封装问题我不想这样做。不过,要明确一点,这就是我的意思:
public class Foo<T>
{
public Foo(T value)
{
Value = value;
}
public T Value { get; }
}
打印结果更接近我想要的:
> new Foo<string>("bar")
Foo<string> { Value="bar" }
但是,正如我所写,我不想添加 public 属性。
如何让它表现得像下面这样?
> new Foo<string>("bar")
Foo<string> { "bar" }
> new Foo<int>(42)
Foo<int> { 42 }
请注意,当使用除字符串以外的任何其他内容时(例如 int
),不应有引号。
如果您可以像第一次尝试那样覆盖 ToString()
,那么您可以在那里做任何您想做的事情。这让您更接近您想要的,您可以根据需要修改它:
public override string ToString()
{
string v = value is string ? $"\"{value}\"" : $"{value}";
string t = typeof(T).Name.ToLower();
return $"Foo<{t}> {{ {v} }}";
}
您可以使用 [DebuggerDisplay]
属性来自定义对象打印。除了覆盖 ToString()
之外,您还可以在此属性中使用任何 methods/properties。例如:
[DebuggerDisplay("{GetDebuggerDisplay(), nq}")]
public class Foo<T>
{
private readonly T value;
public Foo(T value)
{
this.value = value;
}
private string GetDebuggerDisplay()
{
var val = value is string ? "\"" + value + "\"" : value?.ToString();
return $"Foo<{typeof(T).Name.ToLower()}> {{ {val} }}";
}
}
这避免了必须覆盖 ToString()
或使用不同的实现。比如返回T value
.
的字符串表示
您需要添加 switch/case 才能将 class 名称(例如 Int32
转换为 int
。
[DebuggerDisplay]
属性的 nq
部分 removes the quotes around the value。
结果如下:
> new Foo<string>("bar")
Foo<string> { "bar" }
如需进一步参考,请查看 Jared Parson 关于 [DebuggerDisplay]
属性的精彩博客 post:https://blogs.msdn.microsoft.com/jaredpar/2011/03/18/debuggerdisplay-attribute-best-practices/.
正如 Kristian Hellang 所建议的,通过向 class 添加 [DebuggerDisplay]
属性可以简单而轻松地解决此问题:
[DebuggerDisplay("{ value }")]
public class Foo<T>
{
private readonly T value;
public Foo(T value)
{
this.value = value;
}
}
这解决了所有问题:
> new Foo<string>("bar")
Foo<string>("bar")
> new Foo<int>(42)
Foo<int>(42)
> new Foo<DateTime>(new DateTime(2018, 4, 23))
Foo<DateTime>([23.04.2018 00:00:00])
渲染没有使用花括号,而是构造函数指示的普通括号,但我只觉得合适。
考虑这个 MCVE class:
public class Foo<T>
{
private readonly T value;
public Foo(T value)
{
this.value = value;
}
}
当我在 C# Interactive 中评估和打印这样一个对象时,它看起来像这样:
> new Foo<string>("bar")
Foo<string> { }
这没用。我希望它看起来像这样:
Foo<string> { "bar" }
我该怎么做?
我试过像这样覆盖 ToString
:
public override string ToString()
{
return $"Foo{typeof(T)} {{ {value} }}";
}
这不是我想要的结果:
> new Foo<string>("bar")
[Foo<System.String> { bar }]
此输出至少存在三个问题:
- 该值不在引号中。我希望它是
"bar"
而不是bar
. - 类型参数显示为
System.String
而不是string
。 - 整个值都用方括号括起来。这是我最不关心的。
有没有办法让 C# 交互式显示具有自定义格式的对象?
我知道我可以将 public 属性 添加到 class 以显示值,但由于封装问题我不想这样做。不过,要明确一点,这就是我的意思:
public class Foo<T>
{
public Foo(T value)
{
Value = value;
}
public T Value { get; }
}
打印结果更接近我想要的:
> new Foo<string>("bar")
Foo<string> { Value="bar" }
但是,正如我所写,我不想添加 public 属性。
如何让它表现得像下面这样?
> new Foo<string>("bar")
Foo<string> { "bar" }
> new Foo<int>(42)
Foo<int> { 42 }
请注意,当使用除字符串以外的任何其他内容时(例如 int
),不应有引号。
如果您可以像第一次尝试那样覆盖 ToString()
,那么您可以在那里做任何您想做的事情。这让您更接近您想要的,您可以根据需要修改它:
public override string ToString()
{
string v = value is string ? $"\"{value}\"" : $"{value}";
string t = typeof(T).Name.ToLower();
return $"Foo<{t}> {{ {v} }}";
}
您可以使用 [DebuggerDisplay]
属性来自定义对象打印。除了覆盖 ToString()
之外,您还可以在此属性中使用任何 methods/properties。例如:
[DebuggerDisplay("{GetDebuggerDisplay(), nq}")]
public class Foo<T>
{
private readonly T value;
public Foo(T value)
{
this.value = value;
}
private string GetDebuggerDisplay()
{
var val = value is string ? "\"" + value + "\"" : value?.ToString();
return $"Foo<{typeof(T).Name.ToLower()}> {{ {val} }}";
}
}
这避免了必须覆盖 ToString()
或使用不同的实现。比如返回T value
.
您需要添加 switch/case 才能将 class 名称(例如 Int32
转换为 int
。
[DebuggerDisplay]
属性的 nq
部分 removes the quotes around the value。
结果如下:
> new Foo<string>("bar")
Foo<string> { "bar" }
如需进一步参考,请查看 Jared Parson 关于 [DebuggerDisplay]
属性的精彩博客 post:https://blogs.msdn.microsoft.com/jaredpar/2011/03/18/debuggerdisplay-attribute-best-practices/.
正如 Kristian Hellang 所建议的,通过向 class 添加 [DebuggerDisplay]
属性可以简单而轻松地解决此问题:
[DebuggerDisplay("{ value }")]
public class Foo<T>
{
private readonly T value;
public Foo(T value)
{
this.value = value;
}
}
这解决了所有问题:
> new Foo<string>("bar")
Foo<string>("bar")
> new Foo<int>(42)
Foo<int>(42)
> new Foo<DateTime>(new DateTime(2018, 4, 23))
Foo<DateTime>([23.04.2018 00:00:00])
渲染没有使用花括号,而是构造函数指示的普通括号,但我只觉得合适。