【问题标题】:Why do properties of attributes have to be readable?为什么属性的属性必须是可读的?
【发布时间】:2011-11-28 01:56:50
【问题描述】:

考虑以下属性。

internal class NiceAttribute : Attribute
{
  private string _stuff;

  public string Stuff
  {
    set { _stuff = value; }
  }
}

当我尝试使用属性[Nice(Stuff = "test")] 时,编译器会给出以下错误。

'Stuff' 不是有效的命名属性参数。命名属性 arguments 必须是非 readonly、static 或 const 的字段,或 read-write 属性是公共的,不是静态的。

要求属性可读的原因是什么?


更新
我将尝试概述我的用例,以在属性上具有只写属性。

interface ISettingsBuilder
{
  Settings GetSettings();
}

class SettingsAttribute : Attribute, ISettingsBuilder
{
  private readonly IDictionary<string, object> _settings =
    new Dictionary<string, object>();

  public Settings GetSettings()
  {
    // Use _settings to create an immutable instance of Settings
  }

  public string Stuff
  {
    set { _settings["Stuff"] = value; }
  }

  // More properties ...
}

ISettingsBuilder 可能还有其他实现。例如,它提供了一个很好的 API 来通过代码构建设置。

我最终通过抛出 NotImplementedException 来实现我的 getter。

  public string Stuff
  {
    get { throw new NotImplementedException(); }
    set { _settings["Stuff"] = value; }
  }

你能想出更好的方法来做这样的事情吗?

【问题讨论】:

  • 现在正是 John Skeet 或 Eric Lippert 出现的好时机。我碰巧看到 Jon Skeet 正在编辑标签 :)
  • 我没有一个好的答案,但您为什么希望它可读?
  • @µBio:因为不需要?该属性可以读取后备存储。如果你愿意的话,它被称为封装。
  • @sehe:我查看了,我检查了规范,我投了赞成票……规范声明它必须是,但没有给出任何理由。
  • 这可能与“命名参数”的工作方式有关吗?它是我们在 C# 4.0 之前拥有的唯一命名参数,并且它的实现可能会强制这种行为,因为它们可能会创建实例然后设置属性/字段。因此它们不能是只读的、静态的或 const 的。如果它是一个属性,它必须有一个 setter。什么的。

标签: c# attributes properties compiler-errors


【解决方案1】:

我怀疑编译器使用了一个稍有误导性的检查来查看您是否在此处访问私有属性

编辑“我们”现在已经找到了实际来源。出于提供信息的目的,这里是完整的细分,但请随意跳到底部。
(注意应该如何针对 Mono 编译器提交错误。我会考虑一段时间)

编译器错误 CS0617

'reference' 不是有效的命名属性参数。命名属性参数必须是非只读、静态或 const 的字段,或非静态的读写属性。

试图访问属性类的私有成员。

它可能似乎正在使用某种查找(类似于反射)来确保 getter可访问,如果它不是,得出的结论是它必须是私有的

当然,它不需要是:)

单声道兼容性:

为了好玩,观察单声道编译器接受这个属性没有任何问题:https://ideone.com/45fCX

因为反射:

当然,编译器可能要求属性参数具有可反映的值。如果该属性不是公开可读的,则只能使用反射来“观察”该属性是否存在,而不是使用它初始化的参数。

我不太清楚,为什么会做出这样的设计选择,但如果考虑到反射的使用,它确实有意义。

更新 @Arun 发布了证实这一猜想的相关引述(谢谢!):

通过反射访问属性 一旦属性与程序元素相关联,就可以使用反射来查询它们的存在和值。查询属性的主要反射方法包含在 System.Reflection.MemberInfo 类(GetCustomAttributes 系列方法)中。

所以原因一定是:属性参数必须有可反映的值

奖品问题:如何使用位置参数?如何反映这些?

【讨论】:

  • +1 为您的更新和 OP 上的 +1,这让我做了一些真正的搜索!关于位置参数的问题,我猜传递的值仅用于构造(因此不一定是正在创建的自定义“属性”的属性)。我怀疑除非定义了属性方法,否则它会被“反映”。
【解决方案2】:

This link 是来自 Visual Studio 2003 的参考,但我猜它几乎没有改变。

来自该链接的相关部分:

通过反射访问属性 一旦属性与程序元素相关联,就可以使用反射来查询它们的存在和值。查询属性的主要反射方法包含在 System.Reflection.MemberInfo 类(GetCustomAttributes 系列方法)中。

【讨论】:

  • 红薯。这是一个非常有用的补充报价。 +1。现在……我在想。 that 如何与位置参数一起工作?如何反映这些?
猜你喜欢
  • 1970-01-01
  • 2011-03-01
  • 2011-02-25
  • 2013-10-26
  • 2013-03-05
  • 2021-12-20
  • 1970-01-01
  • 2011-07-13
  • 1970-01-01
相关资源
最近更新 更多