Property with private setter versus get-only-property

假装没事ソ 提交于 2019-11-29 11:05:17

问题


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

public ICommand AddCommand { get; }

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

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

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

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 Screenshots property) and the public private setter property (such as the second 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?


回答1:


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 NavigationService will never be null, hence you don't need to do null checks against NavigationService before using it. Once it leaves the constructor, it can't ever be changed (well, except through reflection).

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 = null and then if you don't have null-checks and access it, you will get a NullReferenceException and if not handled your application crashes.

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).

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 Screenshots is never null and you won't have to write code such as

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.

Hope that cleared it up.




回答2:


Short answer:

public ICommand AddCommand { get; }

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

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-readonly field and can be assigned at any time by any code with access to private members.

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.




回答3:


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


1. public 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; }:

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; }:

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 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();
}


来源:https://stackoverflow.com/questions/31928978/property-with-private-setter-versus-get-only-property

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!