为什么不能在属性中使用字符串插值?

Why can't I use string interpolation in an attribute?

我正在用 C# 6.0 编写单元测试 (MSTest),我注意到编译器处理属性中的字符串插值的方式有些奇怪。

为什么这样做:

[TestCategory(nameof(MyClass) + "-UnitTest")]

什么时候没有?

[TestCategory($"{nameof(MyClass)}-UnitTest")]

忽略这可能不是对我的测试进行分类的好方法这一事实;我很好奇为什么编译器允许一个而不允许另一个。

内插字符串不是常量值。该值是在运行时确定的,即使在您的情况下所有输入都可以在编译时计算。

字符串插值发生在 runtime and attributes are present in compile time。 所以你的编译器无法解决这个问题,因为它会像这样编译:

[TestCategory(new FormattableString
  {
    Format = "{0}-UnitTest",
    Args = new object[] { nameof(MyClass)}
  })]

属性参数必须是编译时常量。虽然 nameof() 是一个常量(参见 Is nameof() evaluated at compile-time?),但字符串插值功能本身不是。

An interpolated string expression creates a string by replacing the contained expressions with the ToString represenations of the expressions’ results.

当编译器遇到内插字符串时,它会立即将其转换为对 String.Format 的调用,所以...

[TestCategory($"{nameof(MyClass)}-UnitTest")]

变成...

[TestCategory(string.Format("{0}-UnitTest", nameof(MyClass)))]

Attributes require that their arguments be constant expressions 但是上面的表达式直到执行时才会被计算,因此错误...

CS0182 An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type...

知道所有信息在编译时可用,但编译器不够聪明,无法弄清楚。

nameof 与内插字符串有点不同,因为它是 evaluated at compile-time,所以没有错误。