Docs: Attribute parameter types: The documentation claims string arrays are allowed, but they are not.

Created on 19 Jun 2020  Â·  3Comments  Â·  Source: dotnet/docs

Here:

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/attributes#attribute-parameter-types

The docs say:

The types of positional and named parameters for an attribute class are limited to the attribute parameter types, which are:

  • One of the following types: bool, byte, char, double, float, int, long, sbyte, short, string, uint, ulong, ushort.
    [...]
  • Single-dimensional arrays of the above types.

The String type is listed in the first bullet point, and the docs claim we can therefore use an array of strings, but a string array is not allowed, producing a CS0182 compile time error:

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

Thanks


Document Details

⚠ Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

  • ID: 336afb22-5d56-e3a4-0389-564748e9af6e
  • Version Independent ID: d7c118fe-bdab-ca0a-795c-f4ece0af5562
  • Content: Attributes - C# language specification
  • Content Source: spec/attributes.md
  • Product: dotnet-csharp
  • Technology: csharp-spec
  • GitHub Login: @dotnet-bot
  • Microsoft Alias: wiwagn
Area - C# Guide P2 Pri2 csharp-spetech doc-enhancement dotnet-csharprod

Most helpful comment

They are allowed, the following code compiles fine for me:

```c#
using System;

class FooAttribute : Attribute
{
public FooAttribute(string[] strings) {}
}

[Foo(new string[] { "bar", "baz" })]
class C { }
```

Can you share the code that's causing the error?

All 3 comments

They are allowed, the following code compiles fine for me:

```c#
using System;

class FooAttribute : Attribute
{
public FooAttribute(string[] strings) {}
}

[Foo(new string[] { "bar", "baz" })]
class C { }
```

Can you share the code that's causing the error?

Thanks. I am using the InlineData attribute in xunit tests, e.g.

This compiles fine:

[Theory]
[InlineData(new int[] { 2, 5, 7, 8, 12, 16, 32 })]
public void IsSortedAscending_Int_Sorted(int[] arr)
{
    Assert.True(SortUtils.IsSortedAscending(arr));
}

But this does not:

[Theory]
[InlineData(new string[] { "a", "b", "c", "d", "e" })]
public void IsSortedAscending_Int_Sorted(string[] arr)
{
    Assert.True(SortUtils.IsSortedAscending(arr));
}

However, I see now that InlineDataAttribute has only one constructor:

[AttributeUsage(AttributeTargets.Method,AllowMultiple = true)]
[CLSCompliant(false)]
[DataDiscoverer("Xunit.Sdk.InlineDataDiscoverer","xunit.core")]
public sealed class InlineDataAttribute : DataAttribute
{
    public InlineDataAttribute(params object[] data);
}

So I guess the error is specific to that particular Attribute implementation and it's use of the 'params' keyword. Which just leaves the compiler error being a bit misleading in this particular situation...

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

I.e. I did supply an "array creation expression of an attribute parameter type".

Well, ok, it's a minor corner case I guess so happy to close this if you are :) Thanks for the quick response.

Based on the following comment in the compiler code, I believe this is an intentional quirk of the compiler:

```c#
// NOTE: As in dev11, we don't allow array covariance conversions (presumably, we don't have a way to
// represent the conversion in metadata).

To explain in more detail: When you have an attribute `[InlineData(e)]`, [it's interpreted the same as if you wrote `new InlineDataAttribute(e)` in regular code](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/attributes#compilation-of-an-attribute). For the `int` array, that means treating it as the single value in the `params` array, i.e. the compiled form is `new InlineDataAttribute(new object[] { new int[] { 2, 5, 7, 8, 12, 16, 32 } })`. But the `string` array is treated as the whole input array, though a covariant conversion, i.e.: `new InlineDataAttribute((object[])new string[] { "a", "b", "c", "d", "e" })`. Except that covariant conversions can't be used with attributes (as the comment above explains), which is why you get the error.

One way to work around that would be to explicitly specify the outer array:

```c#
[InlineData(new object[] { new string[] { "a", "b", "c", "d", "e" } })]

This means that the document you linked to is not wrong. Though it doesn't specify the limitation on covariant conversion, maybe it should? Also, the error message does not actually tell you what's wrong with your code and that could be improved.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

LJ9999 picture LJ9999  Â·  3Comments

gmatv picture gmatv  Â·  3Comments

LJ9999 picture LJ9999  Â·  3Comments

FrancescoBonizzi picture FrancescoBonizzi  Â·  3Comments

mekomlusa picture mekomlusa  Â·  3Comments