C#非持久`static`关键字?

时间:2009-09-08 15:05:07

标签: c# asp.net static unique

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

怎么可能这样做?

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

就像有人带着

去了一个页面
static int i=0;
page_load...{
  lbl.Text=i;
  i++;
}

然后他们会得到0.如果其他人去了同一个页面,他们也会得到0.但是也有静态属性,所以在类的所有实例中它都是相同的。

6 个答案:

答案 0 :(得分:4)

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

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

我认为最好的办法是创建一个实例级属性,然后执行传递实例并更新计数器所需的内容。

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

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

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

答案 1 :(得分:3)

没有真正干净的方法,但如果您的对象始终存在于HTTP页面/请求的上下文中,您可以使用当前HttpContext的{​​{3}}:

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; }
    }
}

答案 2 :(得分:1)

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

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

我会做的是这样的事情

public class PageBase : Page
{

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

将页面更改为继承自PageBase

编辑:在查看ASP.NET内部对[ThreadStatic]的影响后,我发现Scott Hanselmen撰写的这篇博文中,不,不,不! A tale of two techniques: The [ThreadStatic] Attribute and System.Web.HttpContext.Current.Items。他还指出了HttpContext的存在,它有一个你可以存储对象的内置字典。我完全忘记了这一点,因为到目前为止我从来没有发现任何有用的东西。

答案 3 :(得分:0)

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

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

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

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

答案 4 :(得分:0)

您要求的是ThreadStatic变量,但这不是一个好的解决方案。它会工作,但它不是一个强有力的方法来处理它。例如,ThreadStatic变量仅为第一个线程初始化,因此您需要自己处理每个线程的初始化。

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

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

答案 5 :(得分:0)

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

要执行您想要执行的操作,您需要声明一个对象的应用程序scopped变量,该变量是线程安全的。下面的示例示例将为您提供所有页面的唯一编号。

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

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
}

潜在的问题: 如果您在服务器场中部署它或者您有多个工作进程,请确保您的会话模式是状态服务器或基于SQL Server,因为如果它是InProc,则处理请求的每个服务器/进程将拥有自己的计数器。