21

I'm writing unit tests (MSTest) in C# 6.0 and I noticed something strange in the way the compiler handles string interpolation in attributes.

Why does this work:

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

When this doesn't?

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

Ignoring the fact that this might not be a great way to categorize my tests; I'm curious why the compiler allows one and not the other.

Nate Barbettini
  • 51,256
  • 26
  • 134
  • 147

4 Answers4

15

When the compiler encounters an interpolated string it immediately converts it into a call to String.Format so...

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

Becomes...

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

Attributes require that their arguments be constant expressions but the above expression will not be evaluated until execution time hence the error...

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

You know all the information is available at compile time but the compiler is not smart enough to figure it out.

nameof works a bit differently than interpolated strings because it is evaluated at compile-time so there is no error.

Community
  • 1
  • 1
Alex Booker
  • 10,487
  • 1
  • 24
  • 34
6

Interpolated strings are not constant values. The value is determined at runtime, even though in your case all inputs can be calculated at compile time.

Jimmy
  • 27,142
  • 5
  • 87
  • 100
3

An attribute argument has to be a compile-time constant. While nameof() is a constant (see Is nameof() evaluated at compile-time?), the string interpolation feature itself is not.

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

Community
  • 1
  • 1
Jeroen Vannevel
  • 43,651
  • 22
  • 107
  • 170
0

String interpolation happens in runtime and attributes are present in compile time. So your compiler cant resolve this, as it would be compiled like so:

[TestCategory(new FormattableString
  {
    Format = "{0}-UnitTest",
    Args = new object[] { nameof(MyClass)}
  })]
Community
  • 1
  • 1
Alex H
  • 1,424
  • 1
  • 11
  • 25