Rac*_*hel 6 c# dictionary .net-3.5 data-structures
我想创建一个最多可以存储一个对象副本的类。此处存储的所有对象将共享相同的基类,我希望能够根据其类型获取对象。
到目前为止,我已经提出了这个解决方案,但是我觉得使用Type作为Dictionary键会出错。
在多个模块中使用的基类
interface ISessionVariables { }
Run Code Online (Sandbox Code Playgroud)
用于访问的普通单例类的示例
public class SessionVariables
{
private object _sync = new object();
private Dictionary<Type, ISessionVariables> _sessionVariables =
new Dictionary<Type, ISessionVariables>;
public T Get<T>()
where T : ISessionVariable, new()
{
lock (_sync)
{
ISessionVariables rtnValue = null;
if (_sessionVariables.TryGetValue(typeof(T), out rtnValue))
return (T)rtnValue;
rtnValue = new T();
_sessionVariables.Add(typeof(T), rtnValue);
return (T)rtnValue;
}
}
}
Run Code Online (Sandbox Code Playgroud)
这样我可以从各个模块中这样称呼它
SessionVariableSingleton.Get<ModuleASessionVars>().PropertyA;
SessionVariableSingleton.Get<ModuleCSessionVars>().PropertyC;
Run Code Online (Sandbox Code Playgroud)
这是存储这种数据结构的可接受方法吗?还是有一个更好的选择,使用没有类型键的列表或字典?
有一个问题:它不是线程安全的。鉴于您似乎通过单例使用它,我想您确实需要它是线程安全的。
如果您使用 .NET 4,最好使用ConcurrentDictionary. 否则,添加锁定。
该ConcurrentDictionary代码是这样的:
internal class SessionVariables
{
private readonly ConcurrentDictionary<Type, ISessionVariables> dictionary
= new ConcurrentDictionary<Type, ISessionVariables>();
internal ISessionVariable Get<T>() where T : ISessionVariable, new()
{
return dictionary.GetOrAdd(typeof(T), _ => new T());
}
}
Run Code Online (Sandbox Code Playgroud)
(我也会尽可能避免单身人士,但那是另一回事。)
编辑:专门解决使用类型作为字典键的问题:是的,没关系。事实上,您对引用相等没问题,因为Type对象实际上是规范的 -无论您如何要求,都只有一个Type对象来表示特定 中的特定类型AppDomain。(这在使用 CodeDOM 动态生成的程序集中可能不是真的……不确定。但对于正常情况应该没问题。)
是的Type是罚款作为重点; 但是,线程安全是一个问题-在许多方面,线程安全性要Hashtable好得多。但是,有一个更好的选择,因为您使用的是泛型:cheat:
class SessionVariables {
static class Cache<T> where T : ISessionVariable, new() {
public static readonly ISessionVariable Value = new T();
}
ISessionVariable Get<T>() where T : ISessionVariable, new() {
return Cache<T>.Value;
}
}
Run Code Online (Sandbox Code Playgroud)
现在,它是完全线程安全的(没有“返回不同的实例”的问题),而没有任何字典成本。
编辑有关HashtableJon 的主题:
Dictionary<TKey,TValue> makes no guarantees on concurrency, so you are required to synchronize all access - including the reads, as another thread doing a write can break a reader (you can force this in an example, but like most thread-races, it is hard to reproduce).
By contract, Hashtable guarantees that it is safe for any number of readers, plus at most one writer. From MSDN:
Hashtable is thread safe for use by multiple reader threads and a single writing thread. It is thread safe for multi-thread use when only one of the threads perform write (update) operations, which allows for lock-free reads provided that the writers are serialized to the Hashtable.
This means that you can do things like:
var val = (SomeType)hash[key];
if(val == null) {
// not there; actually compute / create the value
val = ...
// and store it for the next access
lock(syncLock) {
hash[key] = val; // note: could do double-check here
}
}
return val;
Run Code Online (Sandbox Code Playgroud)
请注意,上面的读取周期不需要任何同步。只有写入需要同步。还请注意,因为Hashtable使用object,所以当键和值是类(而不是结构)时,效果最佳。
是的,现在存在并发词典-但以上方法工作正常。
| 归档时间: |
|
| 查看次数: |
2572 次 |
| 最近记录: |