带params object []构造函数的属性产生不一致的编译器错误 [英] Attribute with params object[] constructor gives inconsistent compiler errors

查看:72
本文介绍了带params object []构造函数的属性产生不一致的编译器错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了错误

属性参数必须是属性参数类型的常量表达式,typeof表达式或数组创建表达式

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

请注意以下屏幕截图:

请注意,如果我将DataRow属性与一个或三个参数一起使用,则不会出现编译错误.但是,如果我使用两个参数,而第二个参数是字符串数组,则会收到编译错误.

Notice that if I use the DataRow attribute with one or three parameters, I don't get a compile error. But if I use two parameters and the second parameter is an array of strings, then I do get a compile error.

第一个没有问题,但是第二个似乎变得困惑.

The first one gives me no problem, but the second one seems to be getting confused.

我认为params object[]可能会引起一些混乱. 也许无法确定我是说[DataRow(new[] { 1 }, new[] { "1" })]还是[DataRow(new[] { 1 }, "1")]

I considered that maybe the params object[] could be causing some confusion. Maybe it couldn't determine whether I meant [DataRow(new[] { 1 }, new[] { "1" })] or [DataRow(new[] { 1 }, "1")]

为解决此问题,我尝试将第二个属性强制转换为object([DataRow(new[] { 1 }, (object)new[] { "1" })]),但错误并没有消失,它警告我强制转换是多余的.我还尝试显式指定数组的类型,但这也无济于事.

To resolve that, I tried to cast the second attribute to object ([DataRow(new[] { 1 }, (object)new[] { "1" })]), but the error didn't go away and it warned me that the cast was redundant. I also tried specifying the types of the array explicitly, but that also did not help.

我可以添加第三个虚拟参数,即使null似乎也可以解决此问题,但这只是一种解决方法.正确的方法是什么?

I could just add a third dummy parameter, even null seems to fix this, but that's just a workaround. What's the correct way to do this?

推荐答案

tldr:

正确的解决方法是告诉编译器不要使用扩展形式:

The correct workaround is to tell the compiler to not use the expanded form:

[DataRow(new[] { 1 }, new object[] { new[] { "1" } })]

分析过多:

迈克尔·兰德尔的答案基本上是正确的.让我们通过简化示例来进行深入研究:

The answer of Michael Randall is basically correct. Let's dig in by simplifying 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])] // ERROR
    [MyAttribute(new object[0])]
    [MyAttribute(new string[0], new string[0])]  
    public static void Main() { }
}

让我们首先考虑非错误情况.

Let's first consider the non error cases.

    [MyAttribute()]

标准格式的参数不足.构造函数以其扩展形式适用.就像您已经编写的那样,编译器将其编译为:

There are not enough arguments for the normal form. The constructor is applicable in its expanded form. The compiler compiles this as though you had written:

    [MyAttribute(new object[0])]

接下来,怎么办

    [MyAttribute(new int[0])]

?现在,我们必须确定构造函数是适用于其常规形式还是扩展形式.由于int[]不能转换为object[],因此它不适用于普通形式.它以扩展形式适用,因此就像您编写的一样被编译

? Now we must decide if the constructor is applicable in its normal or expanded form. It is not applicable in normal form because int[] is not convertible to object[]. It is applicable in expanded form, so this is compiled as though you'd written

    [MyAttribute(new object[1] { new int[0] } )]

现在怎么办

    [MyAttribute(new object[0])]

构造函数可以以其正常形式和扩展形式使用.在这种情况下,正常形式将获胜.编译器按编写的方式生成调用.它不会将对象数组包装在第二个对象数组中.

The constructor is applicable in both its normal and expanded form. In that circumstance the normal form wins. The compiler generates the call as written. It does NOT wrap the object array in a second object array.

    [MyAttribute(new string[0], new string[0])]  

?普通形式的参数过多.使用扩展形式:

? There are too many arguments for the normal form. The expanded form is used:

    [MyAttribute(new object[2] { new string[0], new string[0] })] 

这应该很简单.那是怎么回事:

That should all be straightforward. What then is wrong with:

    [MyAttribute(new string[0])] // ERROR

?好吧,首先,它是否可以正常或扩展形式使用?显然,它可以扩展形式应用.不太明显的是它也可以正常形式应用. int[]不会隐式转换为object[],但是string[]可以!这是一个不安全的协变量数组引用转换,它在最差的C#功能"列表中排名第一.

? Well, first, is it applicable in normal or expanded form? Plainly it is applicable in expanded form. What is not so obvious is that it is also applicable in normal form. int[] does not implicitly convert to object[] but string[] does! This is an unsafe covariant array reference conversion, and it tops my list for "worst C# feature".

由于超载分辨率说明这适用于普通形式和扩展形式,因此普通形式将获胜,并且就像您编写的那样进行编译

Since overload resolution says that this is applicable in both normal and expanded form, normal form wins, and this is compiled as though you'd written

[MyAttribute((object[]) new string[0] )] // ERROR

让我们探索一下.如果我们修改上面的一些工作案例:

Let's explore that. If we modify some of our working 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] })]

所有这些现在在早期版本的C#中失败,而在当前版本中成功.

All of these now fail in earlier versions of C# and succeed in the current version.

显然,编译器以前允许对对象数组进行 no 转换,甚至不允许进行身份转换.现在,它允许身份转换,但协变量数组转换.

Apparently the compiler previously allowed no conversion, not even an identity conversion, on the object array. Now it allows identity conversions, but not covariant array conversions.

允许通过编译时间常数值分析处理的广播;你可以做

Casts that can be handled by the compile time constant value analysis are allowed; you can do

[MyAttribute(new int[1] { (int) 100} )]

如果愿意,因为该转换已被常量分析器删除.但是属性分析器不知道如何对object[]进行意外的强制转换,因此会产生错误.

if you like, because that conversion is removed by the constant analyzer. But the attribute analyzer has no clue what to do with an unexpected cast to object[], so it gives an error.

您提到的另一种情况呢? 这很有趣!

What about the other case you mention? This is the interesting one!

[MyAttribute((object)new string[0])]

再说一次.这仅适用于其扩展形式,因此应像您编写的那样进行编译

Again, let's reason it through. That's applicable only in its expanded form, so this should be compiled as though you'd written

[MyAttribute(new object[1] { (object)new string[0] } )]

但是那是合法的.为了保持一致,这两种形式都应该合法,或者两种都应该非法(坦率地说,我并不真正在意这两种方式),但是奇怪的是,一种形式是合法的,而另一种形式是非法的.考虑报告错误. (如果这实际上是一个错误,则可能是我的错.很抱歉.)

But that is legal. To be consistent, either both these forms should be legal, or both should be illegal -- frankly, I don't really care either way -- but it is bizarre that one is legal and the other isn't. Consider reporting a bug. (If this is in fact a bug it is probably my fault. Sorry about that.)

它的长短是:将params object []与数组参数混合在一起是造成混乱的秘诀.尽量避免它.如果您遇到将数组传递给params object []方法的情况,请以其正常形式调用它.制作一个new object[] { ... }并将您自己的参数放入数组中.

The long and the short of it is: mixing params object[] with array arguments is a recipe for confusion. Try to avoid it. If you are in a situation where you are passing arrays to a params object[] method, call it in its normal form. Make a new object[] { ... } and put the arguments into the array yourself.

这篇关于带params object []构造函数的属性产生不一致的编译器错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆