使用下面的代码,Resharper会在构造函数中发出'虚拟成员调用'警告:
public class UserDetailViewModel : Screen
{
public UserDetailViewModel()
{
// DisplayName is a virtual member of Screen
DisplayName = "User Details";
}
}
然而,如果我更改代码,就像这样,警告就会消失:
public class UserDetailViewModel : Screen
{
public UserDetailViewModel()
{
SetName();
}
private void SetName()
{
DisplayName = "User Details";
}
}
为什么一个人发出警告而另一个没有?第二种方式是否在某种程度上是正确的,还是仅仅超出了ReSharper可以检测到的潜在危险的极限?
答案 0 :(得分:13)
这只是ReSharper的限制。它应用了一堆启发式方法来查找它可以警告的代码,但它找不到所有内容。这样做需要解决暂停问题。这不可行。
这里的教训非常简单:
没有警告并不意味着没有什么值得警告的。
答案 1 :(得分:3)
在Caliburn.Micro中,通常通过覆盖OnInitialize()方法来设置DisplayName,例如。
protected override void OnInitialize()
{
DisplayName = "User Details";
base.OnInitialize();
}
OnInitialize()仅被调用一次,并且您不再在Resharper中发出警告。另请参阅here。
答案 2 :(得分:1)
由于在以下情况下可能出现的问题而发出警告
派生类型UserDetailViewModel
的对象,说“ConcreteModel”正在构建
ConcreteModel
会覆盖Screen.DisplayName
属性。在属性的set方法中,它取决于已构造完成的ConcreteModel
,比如它访问在构造函数中初始化的另一个成员。
在这种情况下,上面的代码将引发异常。
解决此问题的正确方法是在DisplayName
中声明sealed
为UserDetailViewModel
。现在您可以放心地忽略警告。
以下示例演示了它。取消注释Der
中的行会导致编译错误。
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; }
//}
}