只读自动实现属性是否可行?

63

我在 MSDN 上找到了一个主题,说明可以实现这一点。

我进行了一个测试,似乎打破了这个说法:

using System;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            Foo f = new Foo("1");
            Console.WriteLine(f.Bar); // prints 1
            f.Test("2");
            Console.WriteLine(f.Bar);// successfully prints 2
        }
    }

    class Foo
    {
        public Foo(string b)
        {
            this.Bar = b;
        }

        public string Bar { get; private set; }

        public void Test(string b)
        {
            // this would be impossible for readonly field!
            // next error would be occur: CS0191 or CS0191
            // A readonly field cannot be assigned to (except in a constructor or a variable initializer)
            this.Bar = b; 
        }
    }
}

我的哪里出问题了?


4
我认为你在测试错误的只读属性。你的代码仅表示不允许从类外部或子类直接设置属性“Bar”(私有 setter)。但如果 setter 是私有的,你的类方法仍然可以更改该变量。 - user253984
3
@peterchen:这不是自动实现的属性。 - Brian
1
Mods: 重复问题:https://dev59.com/fHNA5IYBdhLWcg3wNa-T 和 https://dev59.com/cHI_5IYBdhLWcg3wEe1u - Loren Pechtel
1
@Loren:我的问题(以及对它的回答)在总结中得到了比这两个更多的赞同。 - abatishchev
2
@abatishchev:也许他们的问题应该合并到你的问题中。我遇到了这个问题,发现谷歌搜索结果1、2和3都是这里的三个问题! - Loren Pechtel
显示剩余3条评论
7个回答

105

下面的答案是在2010年写的。 在C#6中(发布于2015年),你可以编写只读自动实现属性:

// This can only be assigned to in a constructor
public int Foo { get; }
你说得没错。目前无法正确实现只读自动属性。将setter设为private并不等同于只读属性,无论某些书籍和MSDN可能会怎么说 :)
如果我统治世界,就不会这样了。如果您在6月份看到一些语言设计师(请一起来!)在NDC 2010上,我打算劝服、贿赂、哄骗并让自己变成一个恼人的人,直到他们同意。毕竟,只是一个“薄薄”的功能。
看看那篇MSDN文章,文本本身并没有说它创建了一个只读自动属性。它使用自动属性创建一个不可变类型,这是正确的。唯一有问题的是注释中的部分。
// Read-only properties.

......这些明显是错误的。框架也同意我们的看法:

var prop = typeof(Contact).GetProperty("Name");
Console.WriteLine(prop.CanWrite); // Prints True

27
你不必说服我们这是个好主意,我们知道这是个好主意。问题是:(1)在我们拥有的时间和资金预算内,这是否是我们可以做到的最佳功能?(2)我们是否可以将这个预算用于解决一些更广泛、更困难、不那么“单薄”的不可变性方面的问题,其中不可变的 props 只是一个简单的特殊情况?每个狭义的“专用”功能都会增加语法的复杂性;我们想确保我们为这额外的复杂性获得了良好的价值。 - Eric Lippert
17
@Eric:我对所有方面都理解了,并且任何试图解决更广泛的不可变性问题的尝试都将非常受欢迎。我可能应该向其他人指出,Eric已经在几乎每一种人类交流媒介中都耐心地听取了我的功能请求 :) 不过,值得庆幸的是,往往难以添加功能的一件事情是:它使想象力丰富的团队很难添加太多功能,以至于我们这些凡人跟不上。 - Jon Skeet
1
@Shimmy: 是的,我相信如此。 - Jon Skeet
1
@Shimmy:请使用FieldInfo.IsInitOnly - Jon Skeet
1
@xport:现在是这样的 - 当只读自动实现属性首次引入时并非如此。 - Jon Skeet
显示剩余13条评论

9

这个属性在 Foo 类之外是只读的。我认为文章的意思就是这样。

但它并不等同于使用 readonly 关键字标记变量。


6

有些令人困惑。您应该将只读区分为 c# 的 readonly(关键字的含义)。

  • 只读:它们意味着外部无法直接写入,只能读取。
  • c# 的 readonly:您只能在构造函数中写入它,之后永远不能再写入。

2
@abatischchev 在C#中有一个readonly关键字,这就是我所指的。 - Samuel Carrijo
@persuade:是的,我也在谈论它。我的意思是,在C#中,没有readonly关键字的情况下,某些内容并不是只读的。最好用其他方式来称呼它。 - abatishchev
Java关键字“final”可能比“readonly”更加恰当。显然它并不是真正的只读,因为你可以在构造函数中设置它。 - Stephen Holt
“get-only” 怎么样? - binki

4
不,无法将自动实现的属性设置为只读。对于您提供的页面:
使用自动实现的属性,需要get和set访问器。
只读属性没有set访问器。
没有set访问器的属性被认为是只读的。

3

私有设置不同于只读

与方法或字段类似,private关键字使setter的可见性仅对类本身可用。其他对象无法使用setter,但是类本身的方法可以自由调用它。因此,您的测试代码编译并正常工作。

对外部对象来说,它看起来像一个只读属性,但它并不符合真正的只读定义。


1
无法创建只读的自动实现属性。如果您尝试编译具有自动实现属性的类,并且它没有get和set,则会收到此错误: 'ProjectName.ClassName.Property.get'必须声明一个主体,因为它未标记为abstract或extern。自动实现属性必须同时定义get和set访问器。 我们关注的是以“自动”开始的那个句子。

1

在C#和VB中,ReadOnly关键字应用于字段时具有相同的作用。它们使得该字段只能在静态初始化期间(如果它被标记为静态/共享字段)或构造函数期间进行赋值。

C#不会将readonly关键字用于其他任何内容。

当ReadOnly关键字应用于属性时,VB中的含义与此不同。在这种情况下,它仅意味着没有可接受的方法来分配给公共属性(当然,在内部代码中可以修改后备字段)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接