【问题标题】:StackOverflow exception (fundamental architecture flaw)StackOverflow 异常(基本架构缺陷)
【发布时间】:2014-06-24 00:08:50
【问题描述】:

我在 Jon Skeet's great pattern here 之后使用了一个惰性单例。

此对象的目的是提供对应用程序中所有其他方法的引用。

例如,GetTheme(Context.Current.User.Id) 获取当前用户的主题,以及许多其他方法。

我遇到的问题是当对象已经实例化时如何处理状态变化?

即,如果用户访问网站但未登录,则在创建新用户期间使用Context 对象。

但是,登录后,User 对象为空,因为它已经被实例化了。

我尝试通过以下方式处理此问题,使公共属性引用成为检查 null 引用的私有方法,并尝试确定它是否确实应该是 null

不幸的是,这变成了一个无限循环并且每次都崩溃。

我之前尝试过让用户对象本身变得懒惰,但由于某些奇怪的原因,它在调用时不会实例化并保持null

我正在寻找的是,如何让我的 Lazy Singleton 的 User 属性在调用时自行评估,如果它是 null,但能够被填充,则实例化它自己?

条件是,MVC 全局 User 对象属性 User.Identity.Name 不为空,并在加载时传递到会话中以被拉入模型中,并且数据库中存在使用用户名作为用户名的用户键。

public sealed class Context
{
    public static Context Current { get { return lazy.Value; } }
    private static readonly Lazy<Context> lazy = 
      new Lazy<Context>(() => new Context());
    public UserMeta User { get { return _meta(); } }

    private Context()
    {
        Deployment = GetCurrentDeploymentType();
        Device = (Device)HttpContext.Current.Session["CurrentDevice"];
    }

    private UserMeta _meta()
    {
        //If the current object is null, 
        //but the user has been authenticated, populate the object
        if (Current.User == null && 
          !string.IsNullOrEmpty((string)HttpContext.Current.Session["UserEmail"]))
        {
            //check that the user is in the database first
            var _userTry = 
              Sql.Read.UserByEmail((string)HttpContext.Current.Session["UserEmail"]);
            if (_userTry == null)
            {
                return new UserMeta(
                 new UserMeta((string)HttpContext.Current.Session["UserEmail"]));
            }
            return null;
        }
        //If the Current Instance already has a populated User Object, 
        //just use that
        else if (Current.User != null)
            return Current.User;
        else
            return null;
    }
}

【问题讨论】:

    标签: c# design-patterns singleton stack-overflow lazy-evaluation


    【解决方案1】:

    如果你使用私有字段,它会解决问题

    public sealed class Context
    {
        private UserMeta _user = null;
    
        public static Context Current { get { return lazy.Value; } }
        private static readonly Lazy<Context> lazy = new Lazy<Context>(() => new Context());
        public UserMeta User 
        { 
            get 
            {
                if (_user == null) _user =_meta(); 
                return _user;
            }
        }
    
        private Context()
        {
    
        private UserMeta _meta()
        {
          if (!string.IsNullOrEmpty((string)HttpContext.Current.Session["UserEmail"]))
          {
              //check that the user is in the database first
              var _userTry = 
                Sql.Read.UserByEmail((string)HttpContext.Current.Session["UserEmail"]);
              if (_userTry == null)
              {
                return new UserMeta(
                 new UserMeta((string)HttpContext.Current.Session["UserEmail"]));
              }
              return null;
          }
        }
    

    【讨论】:

      猜你喜欢
      • 2017-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-18
      • 2012-06-21
      • 1970-01-01
      • 2015-10-28
      • 1970-01-01
      相关资源
      最近更新 更多