1

我来自 C/C++ 背景,在 C# 中做一些事情时遇到了麻烦。我现在的问题是我需要一个static在 C++ 中工作的关键字。这样该属性对于类的所有实例都是全局的,这就是 C# 所做的。但我不想要的是 C#(/ASP.NET) 中的持久性。我希望静态属性对当前执行页面上的类的所有实例都是全局的。

怎么可能做到这一点?

基本上我使用它是唯一的命名,它只能在当前执行的页面上是唯一的。如果静态属性是持久的,那么在高流量期间整数翻转的可能性要高得多,这可能导致相同的值被使用两次。

就像如果有人去了一个页面

static int i=0;
page_load...{
  lbl.Text=i;
  i++;
}

那么他们将得到 0。如果其他人访问同一页面,他们也会得到 0。但也具有静态属性,因此它在类的所有实例中都是相同的。

4

6 回答 6

4

不幸的是,在这种情况下你将无法得到你想要的,因为你试图结合两个不兼容的概念

  • static 是 C# 中的修饰符,可将成员(方法、属性、字段等)从绑定到实例中释放出来。它的实例更准确地绑定到 AppDomain 中的类型。
  • 特定于当前执行页面的计数器必须与实例相关联

我认为您最好的选择是创建一个实例级属性并执行传递实例和更新计数器所需的操作。

但我仍然有点不清楚你的情况。看起来你可能想要以下任何一个......

  • 特定于当前执行页面实例的属性
  • 特定于执行页面的所有实例的属性
  • 特定于当前会话中页面的所有使用的属性

你能澄清一下哪一个是问题吗?

于 2009-09-08T15:10:07.523 回答
3

没有真正干净的方法可以做到这一点,但是如果您的对象将始终存在于 HTTP 页面/请求的上下文中,您可以使用current的Items集合HttpContext

public class YourClass
{
    private static readonly string _itemKey = "Key Goes Here";
    private readonly HttpContext _context;

    public YourClass()
    {
        _context = HttpContext.Current;
        if (_context == null) throw new InvalidOperationException("Boom!");

        // set a default value here if you like...
        if (_context.Items[_itemKey] == null)
        {
            _context.Items[_itemKey] = new YourType("Default Value");
        }
    }

    public YourType NonPersistentStatic
    {
        get { return (YourType)(_context.Items[_itemKey]); }
        set { _context.Items[_itemKey] = value; }
    }
}
于 2009-09-08T15:16:42.697 回答
1

我不确定我是否 100% 理解你的问题,但是......

我相信你真正想要的是在 Session 中存储一个对象。

我会做的是这样的

public class PageBase : Page
{

    public MyObject Foo 
    {
        get { return (MyObject)Session["myobject"]; }
        set { Session["myobject"] = value; }
    }
}

并将您的页面更改为从 PageBase 继承

编辑:在查看了[ThreadStatic]ASP.NET 内部的含义后,我看到了 Scott Hanselmen 的这篇博文,他说,不不不!两种技术的故事: [ThreadStatic] 属性和 System.Web.HttpContext.Current.Items。他还指出了 HttpContext 的存在,它有一个可以存储对象的内置字典。我完全忘记了这一点,主要是因为到目前为止我从未发现任何有用的东西。

于 2009-09-08T15:11:37.117 回答
0

您从哪里引用“静态”?如果它只是子控件,我会向您的页面类添加一个常规实例属性,然后通过子控件上的页面属性引用该变量。

public class DefaultPage : Page {
    public string MyProperty { get; set; }
} 

public class DefaultControl : UserControl {
    //...
    ((DefaultPage)this.Page).MyProperty
    //...
}

老实说,如果我看到这段代码,我会认为设计有点倒退。页面应该为用户控件提供它需要的所有数据。

于 2009-09-08T15:09:37.783 回答
0

您要的是一个 ThreadStatic 变量,但这不是一个好的解决方案。它会起作用,但它不是处理它的可靠方法。例如,ThreadStatic 变量仅针对第一个线程进行初始化,因此您需要自己处理每个线程的初始化。

首先,您应该研究为每个元素提供唯一 ID 的内置功能。例如,如果您有一个中继器以便重复相同的控件,则每次迭代都会获得一个唯一的 id,该 id 会添加到控件 id 之前。您可以使用 ClientID 属性来获取此唯一 ID。

如果您需要自己处理命名,则应使用 Page 类中的成员变量来跟踪命名。您可以在类的构造函数中轻松地初始化变量,并且由于该变量在此之前不存在,因此您可以确定在初始化之前您不会意外使用它。

于 2009-09-08T15:30:21.173 回答
0

不知道你为什么需要那个。您可以将会话独有的内容存储在 HTTPContext.Current.Session 中。您可以在 HTTPContext.Current.ViewState 中存储对请求唯一的内容。

要执行您想做的事情,您需要声明一个线程安全对象的应用程序范围变量。下面的示例将为您提供一个跨所有页面的唯一编号。

1) 创建一个线程安全的计数器类,因为应用程序范围的变量默认不是线程安全的

public class ThreadSafeCounter
{
  private object _padlock = new object;
  private int _counterValue = 0;

  public int GetNextValue()
  {
     int temp;
     lock(_padlock)
     {
       _counter++;
       temp = _counter;
     }
     return temp;
  }

}

2) 在 Global.asax Application_Start 事件中创建应用程序变量

HttpContext.Current.Application["MyCounter"] = new ThreadSafeCounter();

3)在您的页面代码中访问它

var counter = HttpContext.Current.Application["MyCounter"] as ThreadSafeCounter;
if (counter != null)
{
  var uniqueValue = counter.GetNextValue();
  // DO SOME WORK HERE
}
else
{
  //throw some exception here
}

一个潜在的陷阱: 如果你在服务器场中部署它或者你有超过 1 个工作进程,请确保你的会话模式是基于状态服务器或 SQL Server,因为如果它是 InProc,则处理请求的每个服务器/进程会有自己的柜台。

于 2009-09-08T20:37:44.233 回答