考虑以下几行代码:
ConcurrentDictionary<string, object> error = new ConcurrentDictionary<string, object>();
error.Add("hello", "world"); //actually throws a compiler error
和
IDictionary<string, object> noError = new ConcurrentDictionary<string, object>();
noError.Add("hello", "world");
我最终弄清楚你所要做的就是改变IL以使Add
函数变为私有。
现在本着解耦代码的精神,我很可能使用接口,但似乎找不到Add
方法的并发字典。
真正使用Add
是否安全(我无法查看IL,因此我不知道它是否真的是线程安全的。)?或者我应该使用具体类型ConcurrentDictionary<TKey, TValue>
并明确使用TryAdd
。
答案 0 :(得分:8)
是的,这很安全。
查看reference source for ConcurrentDictionary。方法IDictionary<TKey, TValue>.Add
只调用TryAdd
并在密钥已存在时抛出异常。
隐藏接口成员并不需要进行IL修改。它可以通过C#中的explicit interface implementation来完成。这是通过不使用方法的访问修饰符并在方法名称前加上接口名称来完成的:
void IDictionary<TKey,TValue>.Add(TKey key, TValue value) {}
这样做有很多原因,也许你不想混淆具体的界面,或者你希望你的类的消费者明确他们使用的是什么方法,如果接口上的方法名称不是'足够具体。此外,它允许您为具有相同签名的不同接口上的方法提供单独的实现(我认为ConcurrentDictionary
并不是真正的问题,但如果您在自己的类中需要它,则可以使用该功能。)
答案 1 :(得分:5)
Hmya,你正在玩一个危险的游戏。 ConcurrentDictionary类的 public 接口提供了线程安全的方法,您可以在调用时感觉良好,并且知道它们表现良好。
但是Add()方法不是这样的方法,只有TryAdd()才是。您收到编译错误,因为Add()不公开,Microsoft 故意通过编写显式接口实现版本使该方法无法访问。否则他们必须做的事情,ConcurrentDictionary实现IDictionary。他们是否已经实现了该接口是有争议的。但他们确实在桥上浇水。
当然,您可以非常轻松地转换为访问Add()。但是现在感觉良好的感觉开始在边缘发展。非常恰当的,他们实现Add()的唯一方法是在TryAdd()失败时抛出异常。带有ArgumentException的Kaboom,祝你好运调试。
当这样的基本操作失败时,您绝对100%确定可以在工作线程上处理异常吗?您是否考虑过在catch子句中需要做什么,而不是考虑攻击IL?如果你这样做,那么当TryAdd()返回false时,它与你编写的代码有什么不同?
没有什么不同。