【问题标题】:Passing static array in attribute在属性中传递静态数组
【发布时间】:2013-05-23 09:42:56
【问题描述】:

是否可以绕过以下限制:

在类中创建一个静态只读数组:

public class A
{
    public static readonly int[] Months = new int[] { 1, 2, 3};
}

然后将其作为参数传递给属性:

public class FooAttribute : Attribute
{
    public int[] Nums { get; set; }

    FooAttribute()
    {
    }
}

--- 假设 Box 是 A 类的属性 ---

[Foo(Nums = A.Months)]
public string Box { get; set; }

我知道这不会编译并且会导致这个错误:

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

是否有可能以某种方式解决这个问题以便能够使用静态数组? 我问是因为这在维护方面会更方便,因为我有很多属性。

提前致谢。

【问题讨论】:

  • 在概念上“readonly”应该是“const”吗?
  • 也许,但他们是different:readonly 关键字与 const 关键字不同。 const 字段只能在字段声明时进行初始化。只读字段可以在声明或构造函数中初始化。因此,只读字段可以根据使用的构造函数具有不同的值。

标签: c# static attributes


【解决方案1】:

基本上没有。

但是,您可以子类化该属性并使用它,即

class AwesomeFooAttribute : FooAttribute {
    public AwesomeFooAttribute() : FooAttribute(A.Months) {}
}

或:

class AwesomeFooAttribute : FooAttribute {
    public AwesomeFooAttribute() {
        Nums = A.Months;
    }
}

并改为使用[AwesomeFoo] 进行装饰。如果您使用反射来查找FooAttribute,它将按预期工作:

[AwesomeFoo]
static class Program
{
    static void Main()
    {
        var foo = (FooAttribute)Attribute.GetCustomAttribute(
            typeof(Program), typeof(FooAttribute));
        if (foo != null)
        {
            int[] nums = foo.Nums; // 1,2,3
        }
    }
}

您也许可以将其嵌套在 A 中,因此您可以使用:

[A.FooMonths]

或类似

【讨论】:

  • 嗯...我想知道:如果您在仅反射的上下文中进行反射会发生什么?
  • @Jon 是的,那你就完蛋了。元数据根本不知道里面发生了什么。如果您只能访问元数据,那么您只能说“有一个AwesomeFooAttribute,我可以说它本身就是一个FooAttribute”。然而,大多数人并没有在仅反射的环境中工作。碰巧的是,我确实做了很多(通常通过 IKVM.Reflection)- 我感觉到你的痛苦 :)
  • 有那么一分钟,我认为代码在某种程度上是等效的,编译器不遗余力地看到该字段是用一个新数组初始化的......理论上这在这个特定的例如,但作为一个功能当然是荒谬的,因为它在很多情况下都不起作用。感谢您解决这个问题。
  • @Jon 确实,这是 99% 的运行时间;但这是一个有用的技巧,因为大多数情况将使用运行时,而不是仅反射
  • @MarcGravell:谢谢 Marc,有趣的解决方案,虽然我不能在构造函数中拥有一个新属性并这样做:-( 但当机会出现时会记住这一点!跨度>
【解决方案2】:

很遗憾,这是不可能的。属性(包括它们的参数的值)由编译器放入程序集元数据中,因此它必须能够在编译时评估它们(因此限制了常量表达式;数组创建表达式的例外显然是因为否则你根本不能有数组参数)。

相比之下,实际初始化A.Months的代码只在运行时执行。

【讨论】:

  • 或者换句话说,属性需要在编译时确定,而readonly vars是在运行时分配的?这种理解正确吗?
【解决方案3】:

简短回答:不。

但是你可以按键引用int数组:

public class A
{
    public static readonly Dictionary<int, int[]> NumsArrays 
              = new[]{{1, new[]{1,1,1}}, {2, new[]{2,2,2}}, {3, new[]{3,3,3}}};
    public const int Num1 = 1;
    public const int Num2 = 2;
    public const int Num3 = 3;
}

public class FooAttribute : Attribute
{
    public int NumsId { get; set; }

    FooAttribute()
    {
    }
}

[Foo(NumsID = A.Num3)]
public string Box { get; set; }

//Evaluation:
int id = (FooAttribute) Attribute.GetCustomAttribute(type, typeof (FooAttribute));
int[] result = A.NumsArrays[id];//result is {3,3,3}

【讨论】:

  • 谢谢,const 帮助
猜你喜欢
  • 1970-01-01
  • 2020-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-14
  • 2018-04-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多