Virtual member call in constructor - why is one okay and the other not?
使用下面的代码,Resharper引发"虚成员调用构造函数"警告:
1 2 3 4 5 6 7 8 | public class UserDetailViewModel : Screen { public UserDetailViewModel() { // DisplayName is a virtual member of Screen DisplayName ="User Details"; } } |
但是,如果我更改了代码,这样的话,警告就会消失:
1 2 3 4 5 6 7 8 9 10 11 12 | public class UserDetailViewModel : Screen { public UserDetailViewModel() { SetName(); } private void SetName() { DisplayName ="User Details"; } } |
为什么一个提出警告而另一个没有?第二种方法是正确的,还是仅仅超出了Resharper检测到的潜在危险的极限?
这仅仅是一个重新竖琴的限制。它应用了一系列的启发式方法来查找可以发出警告的代码,但并不能找到所有的代码。这样做需要解决暂停问题。这是不可行的。
这里的教训很简单:没有警告并不意味着没有什么可警告的。
在caliburn.micro中,通常通过重写oninitialize()方法来设置displayname,例如
1 2 3 4 5 | protected override void OnInitialize() { DisplayName ="User Details"; base.OnInitialize(); } |
OnInitialize()只被调用一次,并且不再在Resharper中引发警告。这里也可以看到。
由于以下情况可能出现的问题而发出警告
一个派生类型为
UserDetailViewModel 的对象,表示正在构造"concreteModel"ConcreteModel 覆盖Screen.DisplayName 属性。在属性的set方法中,它依赖于已完成构造的ConcreteModel ,比如它访问在构造函数中初始化的另一个成员。
在这种情况下,上述代码将引发异常。
解决这个问题的正确方法是在
下面的示例演示了它。取消对
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | class Base { public virtual string DisplayName { get; set; } } class Der : Base { public Der() { // ok to ignore virtual member access here DisplayName ="Der"; } public override sealed string DisplayName { get; set; } } class Leaf : Der { private string _displayName; public Leaf() { _displayName ="default"; } //override public string DisplayName //{ // get { return _displayName; } // set { if (!_displayName.Equals(value)) _displayName = value; } //} } |