TL; DR:
The correct workaround is to tell the compiler not to use the extended form:
[DataRow(new[] { 1 }, new object[] { new[] { "1" } })]
Excessive analysis:
Michael Randall's answer is basically correct. Let me slip in to simplify your example:
using System; [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] public class MyAttribute : Attribute { public MyAttribute(params object[] x){} } public class Program { [MyAttribute()] [MyAttribute(new int[0])] [MyAttribute(new string[0])]
First, consider the cases of errors.
[MyAttribute()]
Not enough arguments for normal form. The constructor is applicable in extended form. The compiler compiles this as if you wrote:
[MyAttribute(new object[0])]
Next how about
[MyAttribute(new int[0])]
? Now we have to decide if the constructor is applicable in its normal or extended form. This is not applicable in normal form, because int[] not converted to object[] . It is applicable in extended form, so it compiled as if you wrote
[MyAttribute(new object[1] { new int[0] } )]
Now how about
[MyAttribute(new object[0])]
The constructor is applicable in both its normal and expanded form. In this case, the normal form wins. The compiler generates the call as written. It does not transfer an array of objects to a second array of objects.
What about
[MyAttribute(new string[0], new string[0])]
? There are too many arguments for a normal form. The extended form is used:
[MyAttribute(new object[2] { new string[0], new string[0] })]
Everything should be simple. What's wrong with it:
[MyAttribute(new string[0])]
? Well, firstly, is it applicable in the usual or expanded form? Simply put, it is applicable in expanded form. What is not so obvious is that it is also applicable in normal form. int[] implicitly converted to object[] , but string[] does! This is an unsafe covariant conversion of array references, and it matches my list of "the worst C # function".
Since overload resolution says that it is applicable in both normal and advanced forms, the normal form wins, and it compiled as if you wrote
[MyAttribute((object[]) new string[0] )]
Let me examine this. If we change some of our work cases above:
[MyAttribute((object[])new object[0])] // SOMETIMES ERROR! [MyAttribute((object[])new object[1] { new int[0] } )] [MyAttribute((object[])new object[2] { new string[0], new string[0] })]
All of them now do not work in earlier versions of C # and succeed in the current version.
Apparently, the compiler previously did not allow conversion, even conversion of identifiers, into an array of objects. Now it allows you to convert identifiers, but not covariant transformations of arrays.
Effects that can be processed by analyzing compile-time values โโare allowed; You can do
[MyAttribute(new int[1] { (int) 100} )]
if you like it because this conversion is removed by a constant parser. But the attribute analyzer does not know what to do with an unexpected click on object[] , so it gives an error.
What about the other case you mentioned? It is interesting!
[MyAttribute((object)new string[0])]
Again, let me reason. This only applies in its expanded form, so it should be compiled as if you wrote
[MyAttribute(new object[1] { (object)new string[0] } )]
But that is legal . To be consistent, both of these forms must be legal, or both must be illegal - to be honest, I don't care, anyway - but it is strange that one is legal and the other is not. Review the error message. (If this is actually a mistake, this is probably my mistake. Sorry.)
Long and short: mixing params [] with array arguments is a recipe for confusion . Try to avoid this. If you are in a situation where you are passing arrays to the params object [] method, call it in its usual form. Make a new object[] { ... } and put the arguments into the array yourself.