C#:所以如果静态类是存储全局状态信息的不良做法,那么提供相同方便性的好方法是什么?

Rek*_*moc 25 .net c# static class global-variables

我一直注意到静态类在用于存储全局信息方面在SO上获得了很多不好的代表.(而且全局变量一般都被嘲笑)我只想知道下面的例子有什么好的选择......

我正在开发一个WPF应用程序,并且根据当前登录用户的ID过滤了从我的数据库中检索到的数据的许多视图.同样,我的应用中的某些点应该只能被视为"管理员"的用户访问.

我目前正在静态类中存储loggedInUserIdisAdmin bool.

我的应用程序的各个部分需要这些信息,我想知道为什么它在这种情况下不理想,以及替代品是什么.起床和跑步似乎非常方便.

我唯一可以想到的替代方法是使用IoC容器将Singleton实例注入需要此全局信息的类中,然后类可以通过其接口与之通信.然而,这是否过度/导致我陷入分析瘫痪?

提前感谢您的任何见解.


更新

因此,我倾向于通过IoC进行依赖注入,因为它可以更好地提供可测试性,因为我可以交换一个服务,如果需要,可以使用模拟提供"全局"信息.我想剩下的是注入的对象是单身还是静态.:-)

如果等待查看是否还有其他讨论,请问问Mark的答案.我不认为这是正确的方式.我只是想看到一些可以启发我的讨论,因为在没有任何建设性的替代方案的情况下,似乎有很多"这是坏的""很糟糕"的陈述在一些类似的问题上.


更新#2 所以我选择了Robert的答案,因为它是一个很好的选择(我认为替代方案是一个奇怪的词,可能是One True Way,因为它是内置于框架中).它并没有强迫我创建一个静态类/单例(尽管它是线程静态的).

唯一让我感到好奇的是,如果我必须存储的"全局"数据与用户身份验证无关,那将如何处理.

Rob*_*son 12

忘记单身人士和静态数据.这种访问模式在某个时候会让你失望.

创建自己的自定义IPrincipal并在适当的登录点替换Thread.CurrentPrincipal.您通常会保留对当前IIdentity的引用.

在用户登录的例程中,例如,您已验证其凭据,请将自定义主体附加到线程.

IIdentity currentIdentity = System.Threading.Thread.CurrentPrincipal.Identity;
System.Threading.Thread.CurrentPrincipal 
   = new MyAppUser(1234,false,currentIdentity);
Run Code Online (Sandbox Code Playgroud)

在ASP.Net也将设置HttpContext.Current.User在同一时间

public class MyAppUser : IPrincipal
{
   private IIdentity _identity;

   private UserId { get; private set; }
   private IsAdmin { get; private set; } // perhaps use IsInRole

   MyAppUser(userId, isAdmin, iIdentity)
   {
      if( iIdentity == null ) 
         throw new ArgumentNullException("iIdentity");
      UserId = userId;
      IsAdmin = isAdmin;
      _identity = iIdentity;          
   }

   #region IPrincipal Members
   public System.Security.Principal.IIdentity Identity
   {
      get { return _identity; }
   }

   // typically this stores a list of roles, 
   // but this conforms with the OP question
   public bool IsInRole(string role)
   {  
      if( "Admin".Equals(role) )
         return IsAdmin;     

      throw new ArgumentException("Role " + role + " is not supported");
   }
   #endregion
}
Run Code Online (Sandbox Code Playgroud)

这是执行此操作的首选方式,并且它在框架中是有原因的.这样您就可以以标准方式访问用户.

如果用户是匿名的(未知)以支持混合匿名/登录身份验证方案的场景,我们还会执行添加属性之类的操作.

另外:

  • 您仍然可以通过注入检索/检查凭据的成员身份服务来使用DI(依赖注入).
  • 您可以使用存储库模式来获取对当前MyAppUser的访问权限(虽然可以说它只是为您投射到MyAppUser,但这可能会带来好处)

  • Thread.CurrentPrincipal ?所以最后你仍然将数据存储在静态成员中...... (2认同)