在 C# 交互式中自定义打印对象



考虑这个MCVE类:

public class Foo<T>
{
private readonly T value;
public Foo(T value)
{
this.value = value;
}
}

当我在C# 交互中计算和打印这样的对象时,它看起来像这样:

> 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 }]

此输出至少存在三个问题:

  1. 该值不在引号中。我希望它是"bar"而不是bar.
  2. 类型参数显示为System.String而不是string
  3. 整个值用方括号括起来。这是我最不关心的问题。

有没有办法使 C# 交互式显示具有自定义格式的对象?

我知道我可以向类添加一个公共属性以显示值,但由于封装问题,我不想这样做。不过,需要明确的是,我的意思是:

public class Foo<T>
{
public Foo(T value)
{
Value = value;
}
public T Value { get; }
}

这打印更接近我想要的:

> new Foo<string>("bar")
Foo<string> { Value="bar" }

但是,正如我所写,我不想添加公共属性。

如何让它的行为如下所示?

> new Foo<string>("bar")
Foo<string> { "bar" }
> new Foo<int>(42)
Foo<int> { 42 }

请注意,当使用字符串以外的任何内容(例如int)时,不应有引号。

可以使用[DebuggerDisplay]属性自定义对象打印。除了覆盖ToString()之外,您还可以在此属性中使用任何方法/属性。例如:

[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的字符串表示形式。

您需要添加一个开关/大小写来将类名(如Int32)转换为int

[DebuggerDisplay]属性的nq部分删除值两边的引号。

结果如下所示:

> new Foo<string>("bar")
Foo<string> { "bar" }

如需进一步参考,请查看 Jared Parson 关于[DebuggerDisplay]属性的优秀博客文章:https://blogs.msdn.microsoft.com/jaredpar/2011/03/18/debuggerdisplay-attribute-best-practices/。

如果你可以像第一次尝试一样覆盖ToString(),那么你可以在那里做任何你喜欢的事情。这可以让您更接近您想要的内容,您可以根据需要对其进行修改:

public override string ToString()
{
string v = value is string ? $""{value}"" : $"{value}";
string t = typeof(T).Name.ToLower();
return $"Foo<{t}> {{ {v} }}";
}

正如 Kristian Hellang 所建议的那样,可以通过向类添加[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])

渲染不使用大括号,而是使用构造函数指示的普通括号,但我只觉得合适。

相关内容

  • 没有找到相关文章

最新更新