如何使这个c#class a单例线程安全

如何使这个c#class a单例线程安全,c#,asp.net,.net,C#,Asp.net,.net,下面是我想做的: public static class MyClass { private Dictionary<string,IDisposable> dict = null; static MyClass() { dict = new Dictionary<string,IDisposable>(); // i fill up the dictionary in a loop here /

下面是我想做的:

public static class MyClass
{

   private Dictionary<string,IDisposable> dict = null;

   static MyClass()
   {
         dict = new Dictionary<string,IDisposable>();

         // i fill up the dictionary in a loop here
         //
   }

   public static UseDictionary(string name)
   {
       var obj = dict[name]        
       obj.DoSomeAction();           
   }

}

static void Main(string[] args)
{
   Parallel.For(0, 1000, x =>
   {               
       // assuming 'name' does exist in the dictionary 
       MyClass.UseDictionary("name"); // randomly throws null reference errors 
   });
}
公共静态类MyClass
{
专用字典dict=null;
静态MyClass()
{
dict=新字典();
//我在这里循环填写字典
//
}
公共静态UseDictionary(字符串名称)
{
var obj=dict[名称]
对象DoSomeAction();
}
}
静态void Main(字符串[]参数)
{
对于(0,1000,x=>
{               
//假设字典中确实存在“name”
MyClass.UseDictionary(“name”);//随机抛出空引用错误
});
}
我基本上希望这个类有一个实例,只初始化字典一次(IDisposable项是一个昂贵的远程连接,我正在打开,我只想打开它一次)

此类将由不同的asp.net页面使用。所以我希望它是线程安全的和单例的。我认为在静态构造函数中初始化字典将使它只被调用一次,并且是线程安全的,不知道为什么会不断出错。有什么想法吗?

看看这里

对不起,:'(通往地狱的路充满了善意

我只想给另一个简单的选择,不需要太多细节

之后的一段时间我也遇到了问题,我发布了这个帖子,最终创建了我自己的版本

我有大约50个内部应用程序和一些使用它的外部提供者

总而言之 在检查了c#中关于单例模式和不同实例的思想之后,我得出结论,一个好的实现是基于用于创建一个实例的内部类,它保证调用构造函数一次,尽管单例类是从多个线程调用的,所以只有一个实例

在vb.net中简化

Public NotInheritable Class ServiceProxySingleton

 Private Sub New()
 End Sub

 Public Shared Function GetInstance() As ServiceProxySingleton
   Return NestedSingletonService._instance
 End Function

  ' Internal class
  Class NestedSingletonService
    Friend Shared ReadOnly _instance As [SingletonClass] = New [SingletonClass]()
    Shared Sub New()
    End Sub
  End Class

End Class

我同意@Leonardo Garcia Crespo的评论。从我这里看到的,你只在静态构造函数中写入字典,每个应用程序域只调用一次。其他所有内容都是读取,如果不修改集合,通用字典支持多个读取器。问题可能只在于我正在编写的代码nvoked。它还需要线程安全。或者,您可以使用另一个关联锁字典并锁定相应的锁,以便一次只能调用一个非线程安全实例

public static class MyClass
{
    public static Dictionary<string,SomeDisposableClass> dict = null;
    public static Dictionary<string,object> locks = null;

    static MyClass()
    {
         // populate the dictionary 
         locks = new Dictionary<string,object>();
         foreach (var key in dict.Keys)
         {
             locks[key] = new object();
         }
    }

    public static void UseDictionary( string name )
    {
        var obj = dict[name];
        var sync = locks[name];
        lock(sync)
        {
            obj.DoSomething();
        }
    }
}
公共静态类MyClass
{
公共静态字典dict=null;
公共静态字典锁=null;
静态MyClass()
{
//填充字典
locks=新字典();
foreach(dict.Keys中的var键)
{
locks[key]=新对象();
}
}
公共静态void UseDictionary(字符串名称)
{
var obj=dict[名称];
var sync=锁定[名称];
锁定(同步)
{
对象。DoSomething();
}
}
}
您也可以使用单例模式,但如果您只有一个静态方法,那么这可能是不必要的。我将注意到,对于使用此类的任何代码来说,这将是非常糟糕的


而且,是的,我知道如果对
name
使用相同的值调用1000次,它将是单线程的。但是,如果调用的方法不是线程安全的,这是您所能做的最好的。这样,至少可以让多个线程同时对
name
的不同值进行操作,因为它们锁定不同ent对象。

以下代码应该是线程安全的,因为.NET保证静态字段初始值设定项的线程安全

private static readonly Dictionary<string,IDisposable> dict = 
                                           CreateAndInitializeDictionary();
private static Dictionary<string,IDisposable> CreateAndInitializeDictionary() {
   var d = new Dictionary<string,IDisposable>();
   .... // here add items 
   return d;
}
专用静态只读字典dict=
CreateAndInitializeDictionary();
私有静态字典CreateAndInitializeDictionary(){
var d=新字典();
..//此处添加项目
返回d;
}

在再次查看您的代码之后,我意识到您的实现也是线程安全的。问题应该在
DoSomething()
:)

中的某个地方,您可以在类上使用同步属性。这就是我为我的一门课所做的。我加入了这些评论,因为它们解释了情况

[Synchronization]
public class IprServerController : ContextBoundObject
{
    // We need to worry about things like a user deleting a route at the same time that another user is starting one.
    // So, instead of trying to lock appropriately throughout the class, we can lock declaratively, by using the
    // Synchronization attribute and deriving from ContextBoundObject. Now only one thread can execute methods on
    // this class at a time.

也许共享错误消息的确切文本会对那些试图帮助您的人有所帮助。从示例中,唯一可能导致此问题的原因是多线程同时调用的DoSomething方法出现了一些问题。可能的重复请查看此处,以获得单例模式的良好解释:通常singleton有一个返回自身的属性“Get”或“Instance”。因此,您可以使用MyClass.Instance.UseDictionary(“名称”)来调用它,这是一个非常繁重的版本,需要下载我建议的其他人的代码。一般来说,最好是自己编写代码并理解它,而不是下载一些东西并插入?(在这种小补丁的情况下)请不要将链接作为答案发布,还要解释链接的内容,这样,如果该链接出现故障,仍然会记录您的答案。好吧,该链接是为纯信息提供的,理解或复制它取决于每一个链接,我还有10-20个静态方法,但我只是举了一个例子。我认为问题可能在于你所说的剂量测定法。我想知道这是否是正确的模式。我试图实现的是使用这个类作为唯一打开连接的地方。此类的任何使用者都不需要担心打开到不同服务器的连接。有没有其他模式可以用来设计这个类?是Sigleton模式更好,还是像我这样使用静态构造函数?特别是对于asp.net网页?@newbie我更喜欢它不是一个单例类或静态类。是的,把逻辑放在一个地方,但是让这个类成为一个普通类。如果操作员