属性get上的null-coalescing运算符

时间:2016-05-26 11:40:47

标签: c#

所以,我reading an article at the moment,我遇到了一些让我质疑它的代码。

代码如下所示:

private UserService _userService = null;

protected UserService UserService
{
    get { return _userService ?? Request.GetOwinContext().GetUserManager<UserService>(); }
}

对我来说,私有属性看起来总是为null,因此使用null-coalescing运算符是没用的。 我认为这样做很有用:

protected UserService UserService
{
    get { return Request.GetOwinContext().GetUserManager<UserService>(); }
}

我错过了什么吗?虽然我们在讨论这个问题,但为什么会这样:

private UserService _userService = null;

肯定和

相同
private UserService _userService;

请帮我澄清一下我的怀疑:D

4 个答案:

答案 0 :(得分:6)

你是对的,私有财产在你的例子中总是为空。

解决问题的一种方法是使用以下代码:

private UserService _userService = null;

protected UserService UserService
{
    get
    {
        return _userService ?? (_userService = Request.GetOwinContext().GetUserManager<UserService>());
    }
}

这样,私有属性在非null时使用,或者初始化为指定的值。执行空合并运算符??之后的语句时,属性实际返回_userService的赋值。

答案 1 :(得分:1)

采用这种方法并不罕见,但通常它带有参数化构造函数,如:

public class X
{
   private UserService _userService = null;

   protected UserService UserService
   {
       get { return _userService ?? Request.GetOwinContext().GetUserManager<UserService>(); }
   }


   public X() { }

   public X(UserService svc) { _userService = svc; }

或其他一些填充服务方法的方法,如方法:

public void SetUserService(UserService svc) { _userSErvice = svc; }

使用像Moq或Rhino.Mocks这样的模拟框架,使用模拟的UserService服务构建的好处。

答案 2 :(得分:0)

我在这里加上我的两分钱:

一个可能的原因是开发人员希望创建使用readonly字段值的_userService属性,如果它仅由用户(di容器)分配,并且如果它不是只需从Identity值提供程序返回值(很可能此提供程序每个http上下文使用单例)。

一般来说,我有点不喜欢在属性的getter方法中分配字段值,因为setter仅出于此目的而存在。

如果我们想要在代码中更改某些内容,以便以正常方式使其变得更加“正常”。我们可以在构造函数中设置此字段并向其添加可选参数:

private UserService _userService;

protected UserService UserService
{
    get
    {
        return _userService;
    }
}

public MyController(UserService service = null)
{
   this._userService = service ?? 
          Request.GetOwinContext().GetUserManager<UserService>();
}

现在代码更可测试且整洁。它还允许我们使用DI框架。这种方法的唯一缺点是我们远离延迟加载。好吧,我们可以再次使用Lazy<T>

private Lazy<UserService> _userService;

protected UserService UserService
{
    get
    {
        return _userService.Value;
    }
}

public MyController(UserService service = null)
{
     service = service ?? 
          Request.GetOwinContext().GetUserManager<UserService>();

     _userService = new Lazy<UserService>(service);
}

现在我们可以更轻松地对代码进行单元测试,我们可以使用DI框架并从使用延迟加载中受益。

P.S。

明确地将null值分配给引用类型字段对我来说没有多大意义。我能想到的唯一原因是它略微提高了可读性,但这似乎完全基于意见。

答案 3 :(得分:0)

如@Rob在评论中所述,这是正常模式

get { return _userService ?? _userService = Request.GetOwinContext().GetUserManager<UserService>(); }

C#8添加了null-coalescing assignment operator,它为此模式添加了一些语法糖:

get { return _userService ??= Request.GetOwinContext().GetUserManager<UserService>(); }

这与_userService ?? _userService =相同。