【问题标题】:C# Static membersC# 静态成员
【发布时间】:2012-02-15 11:34:33
【问题描述】:

我有一个关于非静态类的静态成员和函数的问题。

我的班级中有一个用于身份验证的静态成员。基本上,我从我的 Web 应用程序调用一个静态函数,然后在内部调用一个静态函数,为该静态成员分配一个值。现在我的问题是,每次从我的 Web 应用程序调用静态函数时,都会创建一个对该对象的新引用并为静态成员分配一个新值。

所以基本上我有这个:

public class ClassA
{
     private static int UserId;

     private static AssignIdToUser(string token)
     {
         UserId = <int value depending on result of db query>;
     }

     public SendMessage(string token, string message, string toaddress)
     {
         AssignIdToUser(token);
         Message msg = new Message(); //This is just a sample of a class that is similar to the one I use
         msg.Message = message;
         msg.UserId = UserId;
         msg.ToAddress = toaddress;
         //add class to db and save
     }
}

然后在我的网络应用程序中我可以这样做:

ClassA.SendMessage("userstoken", "This is a message", "0123456789");

现在如果两个用户同时登录并同时调用该函数,那么成员 UserId 是否对每个用户都有正确的值?

基本上是为每个请求创建的对象的实例还是使用相同的对象?

【问题讨论】:

  • 因为类是非静态的,所以为每个用户创建了一个新的类实例
  • @RashmiKantShrivastwa ClassA.SendMessage 行不会创建ClassA 的实例,它只会初始化任何静态成员/在第一次调用时调用静态构造函数。所以你的评论几乎完全不正确。
  • 答案涵盖了您的主要问题(这样做不安全),但也值得对您的最后一行进行评论。对于静态成员,不会创建实例对象,因此您甚至不能说使用了“相同”对象。查看有关此 msdn.microsoft.com/en-us/library/79b3xss3(v=vs.80).aspx 的 MSDN 文档,这对于理解使用静态时至关重要 - 否则很容易将自己开枪打死。

标签: c# .net oop web-applications


【解决方案1】:

每个AppDomain 都会存在一个静态成员的实例,除非您指定[ThreadStatic],在这种情况下它将是每个线程,但总是每个类型 (注意,泛型在这一点上发挥了重要作用!)

静态成员不是 Web 应用程序的好选择,因为 IIS 会定期回收 AppDomain。每次回收时,您都会失去静电。

用户操作通常存储在Session 状态,我将从这里开始。假设 ASP.NET:

Session State on MSDN

Application State on MSDN

【讨论】:

  • .... 和 ThreadStatic 在 ASP.NET 应用程序中可能很危险:stackoverflow.com/questions/4791208/…
  • @gsharp Static 通常很危险,因为 IIS 会随意回收 AppDomain/Processes。我提倡避免,但感谢您提供更多信息。
  • @Armand 你假设不正确。静态函数将在类型上静态调用 - 它不知道实例,因此在静态方法中不允许使用 this 关键字,也不能访问非静态成员。如果您需要保存每个用户的信息,请查看Session 状态,如果您需要为整个应用程序保存它,请查看Application 状态。
  • 同意你的看法。我只是想确定,Armand 不想实现 ThreadStatic 解决方案。
  • @AdamHouldsworth 谢谢,我很感激这一切的清理
【解决方案2】:

静态字段中的值在请求之间共享。每次使用实例字段并创建对象的新实例,或将 UserId 传递给方法。

【讨论】:

    【解决方案3】:

    不,静态成员在所有实例之间共享,因此用户 ID 将是一个不可预测的值。让您的分配函数返回用户 ID 是一个更好的主意,然后您将获得每次调用的正确值。

    即。

    var userId = AssignIdToUser(token);
    ....
    msg.UserId = userId;
    

    【讨论】:

    • 这会解决不可预测的用户 ID 问题吗?或者如何将静态成员更改为非静态成员,然后在每个静态函数中创建对象的实例?
    • @Armand:您将不再需要静态成员 UserId。该函数会将值直接返回给需要它的代码。所以不需要在 SendMessage 之外有一个变量来存储 UserId。
    • @Armand:不,那样不会有任何进一步的可预测行为
    【解决方案4】:

    您使用的函数不是线程保存的。

    如果您有两个对象,一个是两个不同的线程(T1 和 T2)同时执行,则可能发生 SendMessage() 的第一次调用(例如在 T1)在 AssignIdToUser() 之后立即被中断。 如果现在 T2 被安排并完成了一次 SendMessage() 调用,则 T1 中的 SendMessage() 方法将使用与 T2 中的 SendMessage 方法相同的用户 ID。

    你不应该在这个地方使用任何静态变量。但是你可以使用这样的静态函数,例如:

     private static int getUserIdForToken(String token) {
         ...
         return <int value depending on result of db query>;
     }
    

    【讨论】:

      猜你喜欢
      • 2010-12-21
      • 2021-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-20
      相关资源
      最近更新 更多