C# 具有私有setter的属性与仅获取属性

C# 具有私有setter的属性与仅获取属性,c#,wpf,mvvm,c#-6.0,C#,Wpf,Mvvm,C# 6.0,C#6.0引入了定义仅获取属性的功能: public ICommand AddCommand { get; } 现在,当定义另一个类似以下内容的属性时,ReSharper建议将Auto属性设置为“仅获取”: 公共get-only属性(例如第一个AddCommand)、私有get-only属性(例如屏幕截图属性)和公共私有setter属性(例如第二个AddCommand)之间有什么区别 我的WPF应用程序似乎并不关心它的公共属性(UICommand)是否包含私有setter,但肯定有区别吗?在绑

C#6.0引入了定义仅获取属性的功能:

public ICommand AddCommand { get; }
现在,当定义另一个类似以下内容的属性时,ReSharper建议将Auto属性设置为“仅获取”:

公共get-only属性(例如第一个
AddCommand
)、私有get-only属性(例如
屏幕截图
属性)和公共私有setter属性(例如第二个
AddCommand
)之间有什么区别


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

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

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

例如:

public class MainViewModel 
{
    public INavigationService NavigationService { get; }

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

        NavigationService = navigationService;
    }
}
使用此选项时,您可以保证此类不变量,并确保
NavigationService
永远不会为
null
,因此在使用它之前不需要对
NavigationService
执行null检查。一旦它离开构造函数,它就永远不能被更改(好吧,除非通过反射)

在另一边,如果你有

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

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

        NavigationService = navigationService;
    }
}
然后,就有可能(错误地或由没有经验的开发人员)编写代码,而该代码不执行
NavigationService=null
,如果您没有null检查并访问它,您将得到
NullReferenceException
,如果不处理,您的应用程序将崩溃

回到您的示例:如果是
ICommand
。。。通常不访问ViewModel中的命令,只分配它(通常在构造函数中,或者当视图模型的内容发生更改时,如子视图模型发生更改,并且希望将其命令分配给父视图模型命令属性时)

如果是列表:

如果您从未在代码中执行
Screenshots=newlist()
Screenshots=displayshreenshots()
,并且只在构造函数中对其进行初始化,那么出于同样的原因,最好将其设置为只读:这样您就可以保证
Screenshots
永远不为空,并且不必编写诸如

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

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

希望一切都会好起来

简短回答:

public ICommand AddCommand { get; }
将由一个
只读
字段支持,并且在构造函数执行之后,任何C#代码都无法对其进行更改

此外,编译器将生成代码来直接分配支持文件,因为没有属性访问器

另一方面:

public ICommand AddCommand { get; private set; }
将由一个非只读字段支持,并且可以在任何时候由访问私人成员的任何代码分配

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


对外界来说,一个私密的塞特人似乎并不存在。所以,它就像它不存在一样。

编译器为您做了功课后,您的属性会变成什么样子:


1<代码>公共ICommand AddCommand{get;}:

private readonly ICommand <AddCommand>k__BackingField;
public ICommand AddCommand {
    get { return this.<AddCommand>k__BackingField; }
}
private List<Screenshot> <Screenshots>k__BackingField;
private List<Screenshot> Screenshots { 
    get { return this.<Screenshots>k__BackingField; }
    set { this.<Screenshots>k__BackingField = value; } 
}
private ICommand <AddCommand>k__BackingField;
public ICommand AddCommand { 
    get { return this.<AddCommand>k__BackingField; } 
    private set { this.<AddCommand>k__BackingField = value; } 
}
简言之,只能在构造函数中(因为字段是只读的)或通过以下新语法分配公共get-only属性:

public ICommand AddCommand { get; } = new MyCommand(); 
但对于任何其他只读字段,此代码无论如何都会放入构造函数中,因此没有太大区别:

public MyClass1()
{
    this.<AddCommand>k__BackingField = new MyCommand();
}
公共MyClass1()
{
this.k_ubackingfield=新的MyCommand();
}

Get-only属性类似于
readonly
字段,它们可以在对象构造/初始化中设置,但不能在以后设置。私有setter不能保证其他方法在构造后不能修改其值。第一个属性(
AddCommand
)中的“新”是什么?@Amit:set访问器丢失。@RonBeyer因此,对于WPF MVVM,当命令在ViewModel的构造函数中创建时,如果您想说
ICommand
在设置后不会更改,那么最好使用get-only属性?这是一种方法。如果它的好坏是一个意见问题,但如果它没有改变,并且您正在使用C#6,那么如果您试图在意外情况下重新分配它,它可以使事情更容易理解,并给出编译错误。
private List<Screenshot> <Screenshots>k__BackingField;
private List<Screenshot> Screenshots { 
    get { return this.<Screenshots>k__BackingField; }
    set { this.<Screenshots>k__BackingField = value; } 
}
private ICommand <AddCommand>k__BackingField;
public ICommand AddCommand { 
    get { return this.<AddCommand>k__BackingField; } 
    private set { this.<AddCommand>k__BackingField = value; } 
}
public ICommand AddCommand { get; } = new MyCommand(); 
public MyClass1()
{
    this.<AddCommand>k__BackingField = new MyCommand();
}