wpf 具有私有 setter 的属性与仅获取属性的属性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31928978/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 13:19:52  来源:igfitidea点击:

Property with private setter versus get-only-property

c#wpfmvvmc#-6.0

提问by SeToY

C# 6.0 introduces the ability to define get-only properties:

C# 6.0 引入了定义 get-only 属性的能力:

public ICommand AddCommand { get; }

Now when defining another property like the following, ReSharper suggests Auto-property can be made get-only:

现在,在定义如下所示的另一个属性时,ReSharper 建议可以将 Auto-property 设为 get-only

private List<Screenshot> Screenshots { get; set; }

Futhermore, ReSharper doesn't say a thing when defining private getters:

此外,ReSharper 在定义私有 getter 时什么也没说:

public ICommand AddCommand { get; private set; }

What's the difference between a public get-only property (such as the first AddCommand), a private get-only property (such as the Screenshotsproperty) and the public private setter property (such as the second AddCommand)?

公共只获取属性(例如第一个AddCommand)、私有只获取属性(例如该Screenshots属性)和公共私有 setter 属性(例如第二个AddCommand)之间有什么区别?

My WPF application doesn't seem to care whether its public property (UICommand) contains a private setter or no setter at all, but surely there must be a difference?

我的 WPF 应用程序似乎并不关心它的公共属性 (UICommand) 是否包含私有 setter 或根本没有 setter,但肯定有区别吗?

采纳答案by Tseng

In this specific case of binding commands, it doesn't really matter.

在绑定命令的这种特定情况下,这并不重要。

In other cases, i.e. having a class that gets a service injected via constructor and you want to expose it (for whatever reason), it is important to use a read-only properties.

在其他情况下,即有一个通过构造函数注入服务的类,并且您想公开它(无论出于何种原因),使用只读属性很重要。

For example:

例如:

public class MainViewModel 
{
    public INavigationService NavigationService { get; }

    public MainViewModel(INavigationService navigationService) 
    {
        if(navigationService == null)
            throw new ArgumentNullException(navigationServie);

        NavigationService = navigationService;
    }
}

When using this, you guarantee this class invariants and it is assuring that NavigationServicewill never be null, hence you don't need to do null checks against NavigationServicebefore using it. Once it leaves the constructor, it can't ever be changed (well, except through reflection).

使用 this 时,您保证此类不变量,并确保NavigationService永远不会是null,因此NavigationService在使用它之前您不需要对它进行空检查。一旦它离开构造函数,就永远无法更改(好吧,除了通过反射)。

On the other side if you have

在另一边,如果你有

public class MainViewModel 
{
    public INavigationService NavigationService { get; private set; }

    public MainViewModel(INavigationService navigationService) 
    {
        if(navigationService == null)
            throw new ArgumentNullException(navigationServie);

        NavigationService = navigationService;
    }
}

then it's possible to write code (by mistake or by a unexperienced developer) which does NavigationService = nulland then if you don't have null-checks and access it, you will get a NullReferenceExceptionand if not handled your application crashes.

那么有可能编写代码(错误地或由没有经验的开发人员)这样做NavigationService = null,然后如果您没有空检查并访问它,您将得到一个NullReferenceException,如果没有处理您的应用程序崩溃。

Coming back to your example: In case of ICommand... you usually don't access Commands within your ViewModel, only assign it (usually in the constructor or when your view model's content changes, like a child viewmodel changed and you want to assign it's command to the parent viewmodel command property).

回到你的例子:如果ICommand......你通常不会在你的 ViewModel 中访问 Commands,只分配它(通常在构造函数中或当你的视图模型的内容发生变化时,比如子视图模型发生变化并且你想要分配它命令到父视图模型命令属性)。

In case of a list:

如果是列表:

If you never do Screenshots = new List<ScreenShot>()or Screenshots = DisplayScreenshots()in your code and only initialize it in the constructor, then it's indeed better to make it read only for the same reason: Then you can guarantee that Screenshotsis never null and you won't have to write code such as

如果你从不这样做Screenshots = new List<ScreenShot>()Screenshots = DisplayScreenshots()在你的代码中只在构造函数中初始化它,那么出于同样的原因,让它只读确实更好:然后你可以保证它Screenshots永远不会为空并且你不必编写代码,例如

if(Screenshots != null) 
{
    Screenshots.Add(new Screenshot(...));
}

or

或者

if(Screenshot == null) 
{
    Screenshots = new List<Screenshot>();
}

Screenshots.Add(new Screenshot(...));

again and instead always use

再次而不是总是使用

Screenshots.Add(new Screenshot(...));

This has a huge advantage that you need less code, your code is more readable and more maintainable, since you can't "forget" a null-check and risk a NullReferenceException.

这有一个巨大的优势,您需要更少的代码,您的代码更具可读性和可维护性,因为您不能“忘记”空检查并冒NullReferenceException.

Hope that cleared it up.

希望清除它。

回答by Paulo Morgado

Short answer:

简答:

public ICommand AddCommand { get; }

will be backed by a readonlyfield and no C# code will be able to change it beyond the execution of the constructors.

将由一个readonly字段支持,并且除了构造函数的执行之外,任何 C# 代码都无法更改它。

Also, the compiler will generate code to directly assign the backing filed, as there is no property accessor.

此外,由于没有属性访问器,编译器将生成直接分配支持文件的代码。

On the other hand:

另一方面:

public ICommand AddCommand { get; private set; }

will be backed by a non-readonlyfield and can be assigned at any time by any code with access to private members.

将由一个非readonly字段支持,并且可以在任何时间通过任何可以访问私人成员的代码进行分配。

In this case, the compiler will generate normal property setting code.

在这种情况下,编译器会生成正常的属性设置代码。

To the outside world, a private setter is as if it doesn't exist. So, it's the same as if it didn't really exist.

在外界看来,私人二传手就好像不存在一样。所以,就好像它真的不存在一样。

回答by sotonika

Here's what your properties become after compiler did homework for you:

这是编译器为您完成作业后您的属性变成的:


1.public ICommand AddCommand { get; }:


1public ICommand AddCommand { get; }.:

private readonly ICommand <AddCommand>k__BackingField;
public ICommand AddCommand {
    get { return this.<AddCommand>k__BackingField; }
}


2.private List<Screenshot> Screenshots { get; set; }:


2private List<Screenshot> Screenshots { get; set; }.:

private List<Screenshot> <Screenshots>k__BackingField;
private List<Screenshot> Screenshots { 
    get { return this.<Screenshots>k__BackingField; }
    set { this.<Screenshots>k__BackingField = value; } 
}


3.public ICommand AddCommand { get; private set; }:


3public ICommand AddCommand { get; private set; }.:

private ICommand <AddCommand>k__BackingField;
public ICommand AddCommand { 
    get { return this.<AddCommand>k__BackingField; } 
    private set { this.<AddCommand>k__BackingField = value; } 
}

In short, public get-only property can be assigned only in constructor (because the field is read-only) or by this new syntax:

简而言之,public get-only 属性只能在构造函数中分配(因为该字段是只读的)或通过以下新语法:

public ICommand AddCommand { get; } = new MyCommand(); 

but as for any other read-only field, this code is anyway put into constructor, so there is no big difference:

但是对于任何其他只读字段,此代码无论如何都会放入构造函数中,因此没有太大区别:

public MyClass1()
{
    this.<AddCommand>k__BackingField = new MyCommand();
}