C# 为什么属性的属性必须是可读的?

C# 为什么属性的属性必须是可读的?,c#,attributes,properties,compiler-errors,C#,Attributes,Properties,Compiler Errors,考虑以下属性 internal class NiceAttribute : Attribute { private string _stuff; public string Stuff { set { _stuff = value; } } } 当我尝试使用属性[Nice(Stuff=“test”)]时,编译器会给出以下错误 “Stuff”不是有效的命名属性参数。命名属性 参数必须是非只读、静态或常量的字段,或 读写公共而非静态的属性 属性可读性要求背后的理性是什么

考虑以下属性

internal class NiceAttribute : Attribute
{
  private string _stuff;

  public string Stuff
  {
    set { _stuff = value; }
  }
}
当我尝试使用属性
[Nice(Stuff=“test”)]
时,编译器会给出以下错误

“Stuff”不是有效的命名属性参数。命名属性 参数必须是非只读、静态或常量的字段,或 读写公共而非静态的属性

属性可读性要求背后的理性是什么


更新
我将尝试勾勒出在属性上具有只写属性的用例

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 ...
}
你能想出一个更好的方法来做这样的事情吗?

我怀疑编译器使用了一个稍微误导的检查来查看你是否正在访问这里的私有属性

编辑“我们”现在已经找到了实际来源。为了便于参考,这里是完整的细分,但请随意跳到底部
(注意应该如何针对Mono编译器提交bug。我会考虑一下)

编译器错误CS0617
“引用”不是有效的命名属性参数。命名属性参数必须是非只读、静态或常量的字段,或非静态的读写属性

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

它似乎在使用某种查找(类似于反射)来确保getter是可访问的,如果不是,则断定它必须是私有的

当然,这不一定是:)

单声道兼容性: 为了好玩,请注意mono编译器在接受此属性时没有任何问题:

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

我不知道为什么会做出这样的设计选择,但如果你考虑到反射的使用,这是有意义的

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

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

因此原因必须是:属性参数必须具有可反射值

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

是VisualStudio2003的参考资料,但我想它几乎没有改变

该链接的相关部分:

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


现在是约翰·斯基特或埃里克·利珀特出现的好时机。我碰巧看到了Jon Skeet编辑标签的一瞥:)我没有一个好的答案,但为什么你希望它不可读?@µBio:因为它不需要可读?该属性可以读取备份存储。它叫做封装,如果你愿意的话。@sehe:我看了,我检查了规范,我投了赞成票。。。规范规定必须这样做,但没有给出任何理由。这可能与“命名参数”的工作方式有关吗?这是我们在C#4.0之前仅有的命名参数,它的实现可能会强制这种行为,因为它们可能创建实例,然后设置属性/字段。因此,它们不能是只读、静态或常量。如果它是一个属性,它必须有一个setter。或者什么的,红薯。这是一个非常有用的补充引语+1.现在。。。我在想。这是如何与位置参数一起工作的?如何反映这些?+1对于你的更新和+1的OP,它让我做了一些真正的搜索!关于位置参数的问题,我猜传递的值仅用于构造(因此不必是正在创建的自定义“属性”的属性)。除非定义了属性方法,否则我怀疑它是否会得到“反射”。
  public string Stuff
  {
    get { throw new NotImplementedException(); }
    set { _settings["Stuff"] = value; }
  }