Почему компилятор выдает ошибку из-за непостоянного выражения при передаче только строкового массива - PullRequest
3 голосов
/ 24 апреля 2020

Когда я передаю строковый массив в тестовую функцию следующим образом:

[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 ) {
    //...
}

Компиляция работает нормально.

Но, если я удаляю целочисленный параметр, как показано ниже, фрагмент кода показывает:

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

Произошла ошибка компилятора с сообщением An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type.

Я в основном понимаю причину ошибки, что массив не является константным типом. Но почему компилятор принимает массив, если в тестовую функцию передан другой параметр? Это даже работает, если я помещу другой массив в 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 ) {
    //...
}

Ответы [ 2 ]

2 голосов
/ 26 апреля 2020

Давайте упростим это до того, что перегрузка не будет задействована, а также удалим 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 {}

В основном, компилятор не желает предоставлять string[] для параметра object[] в атрибута, даже если это нормально.

Я считаю это ошибка компилятора, проверив spe c - но я не хотел бы сказать наверняка. Выражение new string[] { "a", "b" } считается как атрибут-аргумент-выражение в терминах spe c - и если вы измените тип параметра на string[], оно будет работать нормально. Так что проблема заключается в применении этого типа аргумента к параметру. В spe c также говорится, что параметр и аргумент атрибута «ограничены теми же правилами, что и простое присваивание», но в этом случае это было бы хорошо. Так что я не вижу ничего в заклинании c, которое должно это запрещать.

0 голосов
/ 24 апреля 2020

Похоже на проблему с перегрузкой.

TestCaseAttribute имеет следующие конструкторы:

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

Ваш первый пример соответствует (B), как и ваш третий.

Вы хотите, чтобы второй (неуспешный) соответствовал (A), но на самом деле он совпадает (D)

Попробуйте привести ваш массив к объекту

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

или использовать именованную передачу параметров

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

Правила атрибутов допускают передачу одномерного массива, но только двухмерных массивов (как описано здесь ), поэтому (D) не разрешено с массивом.

...