Why is the compiler giving an error because of a non constant expression when passing just a string array

雨燕双飞 提交于 2020-12-30 08:34:48

问题


When I pass a string array to a test function like this:

[TestCase( new string[] { "1", "2", "3" }, 1 )]
[TestCase( new string[] { "54", "508" }, 1 )]
[TestCase( new string[] { "768" }, 2 )]
public void someTest( string[] someStrings, int someNumber ) {
    //...
}

The compilation works fine.

But, if I remove integer parameter like the follwoing code snippet shows:

[TestCase( new string[] { "1", "2", "3" } )]
[TestCase( new string[] { "54", "508" } )]
[TestCase( new string[] { "768" } )]
public void someTest( string[] someStrings ) {
    //...
}

A compiler error with the message An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type occurs.

I basically get the cause of the error, that an array is not a constant type. But why is the compiler accepting an array, if there is another paramter passed to the test function? It even works, if I put another array inside the TestCase:

[TestCase( new string[] { "1", "2", "3" }, new int[] { 1, 2, 3 } )]
[TestCase( new string[] { "54", "508" }, new int[] { 54, 508 } )]
[TestCase( new string[] { "768" }, new int[] { 768 } )]
public void someTest( string[] someStrings, int[] someNumbers ) {
    //...
}

回答1:


Let's simplify this to something where overloading isn't involved, and also remove params:

using System;

[AttributeUsage(AttributeTargets.All)]
class FooAttribute : Attribute
{
    public FooAttribute(object[] args)
    {
    }
}

// Error
[Foo(new string[] { "a", "b" })]
class FooTest1 {}

// Error
[Foo(new[] { "a", "b" })]
class FooTest2 {}

// Error
[Foo(args: new string[] { "a", "b" })]
class FooTest3 {}

// Error
[Foo((object[]) new string[] { "a", "b" })]
class FooTest4 {}

// Works
[Foo(new object[] { "a", "b" })]
class FooTest5 {}

// Works
[Foo(new[] { (object) "a", "b" })]
class FooTest6 {}

Basically the compiler is unwilling to supply a string[] for a object[] parameter in an attribute, even though that would normally be fine.

I believe this is a compiler bug, having checked the spec - but I wouldn't like to say for certain. The expression new string[] { "a", "b" } does count as an attribute-argument-expression in spec terms - and if you change the parameter type to string[] it works fine. So it's the application of that argument type to the parameter that's the problem. The spec also says that the attribute parameter and argument are "are constrained by the same rules as simple assignment" - but that would be fine in this case. So I can't see anything in the spec that should disallow this.




回答2:


Looks like an overloading issue.

TestCaseAttribute has the following constructors:

TestCaseAttribute(object arg);                             // A
TestCaseAttribute(object arg1, object arg2);               // B
TestCaseAttribute(object arg1, object agr2, object arg3);  // C
TestCaseAttribute(params object[] arguments);              // D

Your first example matches (B) as does your third.

You want the second (failing one) to match (A) but in fact it's matching (D)

Try casting your array to an object

[TestCase( (object) new string[] { "1", "2", "3" } )]

or use named parameter passing

[TestCase( arg: new string[] { "1", "2", "3" } )]

The rules of attributes allow one-dimensional array to be passed, but ont two-dimensional arrays (as described here), so (D) is not allowed with an array.



来源:https://stackoverflow.com/questions/61402943/why-is-the-compiler-giving-an-error-because-of-a-non-constant-expression-when-pa

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!