C#6.0引入了定义只获取属性的功能:
public ICommand AddCommand { get; }
现在,在定义下面的其他属性时,ReSharper建议自动属性可以变为只用:
private List<Screenshot> Screenshots { get; set; }
另外,ReSharper在定义私人吸气者时并没有说出一句话:
public ICommand AddCommand { get; private set; }
公共get-only属性(例如第一个AddCommand
),私有get-only属性(例如Screenshots
属性)与公共私有属性之间的区别是什么? setter属性(例如第二个{{1}})?
我的WPF应用程序似乎并不关心它的公共属性(UICommand)是否包含私有的setter或者根本没有setter,但肯定必须有区别?
答案 0 :(得分:21)
简短回答:
public ICommand AddCommand { get; }
将由readonly
字段支持,除了构造函数的执行之外,没有C#代码能够更改它。
此外,编译器将生成直接分配后备字段的代码,因为没有属性访问器。
另一方面:
public ICommand AddCommand { get; private set; }
将由非readonly
字段支持,并且可以随时通过任何可访问私有成员的代码进行分配。
在这种情况下,编译器将生成正常的属性设置代码。
对外界来说,私人制定者就好像它不存在一样。所以,它就像它确实不存在一样。
答案 1 :(得分:12)
在绑定命令的这种特定情况下,它并不重要。
在其他情况下,即有一个类通过构造函数注入服务并且您想要公开它(无论出于何种原因),使用只读属性很重要。
例如:
public class MainViewModel
{
public INavigationService NavigationService { get; }
public MainViewModel(INavigationService navigationService)
{
if(navigationService == null)
throw new ArgumentNullException(navigationServie);
NavigationService = navigationService;
}
}
使用此功能时,您可以保证此类不变量,并确保NavigationService
永远不会null
,因此在使用NavigationService
之前不需要对public class MainViewModel
{
public INavigationService NavigationService { get; private set; }
public MainViewModel(INavigationService navigationService)
{
if(navigationService == null)
throw new ArgumentNullException(navigationServie);
NavigationService = navigationService;
}
}
进行空检查。一旦它离开构造函数,它就不会被改变(好吧,除非通过反射)。
另一方面,如果你有
NavigationService = null
然后可以编写代码(错误地或由没有经验的开发人员)NullReferenceException
,然后如果你没有空检查并访问它,你将获得ICommand
和如果不处理您的应用程序崩溃。
回到你的例子:如果是Screenshots = new List<ScreenShot>()
...你通常不会访问ViewModel中的命令,只能分配它(通常在构造函数中或当你的视图模型的内容发生变化时,就像孩子一样viewmodel已更改,您希望将其命令分配给父viewmodel命令属性。)
如果是列表:
如果您从未在代码中执行Screenshots = DisplayScreenshots()
或Screenshots
并且仅在构造函数中对其进行初始化,那么最好只将其读取为同样的原因:然后您可以保证{{ 1}}永远不会为null,您不必编写诸如
if(Screenshots != null)
{
Screenshots.Add(new Screenshot(...));
}
或
if(Screenshot == null)
{
Screenshots = new List<Screenshot>();
}
Screenshots.Add(new Screenshot(...));
再次使用
Screenshots.Add(new Screenshot(...));
这有一个巨大的优势,您需要更少的代码,您的代码更易读,更易于维护,因为您不能“忘记”空检查并冒险NullReferenceException
。
希望清理它。
答案 2 :(得分:6)
这是编译器为你完成作业后你的属性变成了什么:
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; }
}
简而言之,只能在构造函数中分配public get-only属性(因为该字段是只读的)或通过这种新语法分配:
public ICommand AddCommand { get; } = new MyCommand();
但是对于任何其他只读字段,此代码无论如何都被放入构造函数中,因此没有太大区别:
public MyClass1()
{
this.<AddCommand>k__BackingField = new MyCommand();
}