隐藏IL中接口的公共成员

dba*_*nes 4 c# il

考虑以下代码行:

ConcurrentDictionary<string, object> error = new ConcurrentDictionary<string, object>();
error.Add("hello", "world"); //actually throws a compiler error
Run Code Online (Sandbox Code Playgroud)

IDictionary<string, object> noError = new ConcurrentDictionary<string, object>();
noError.Add("hello", "world");
Run Code Online (Sandbox Code Playgroud)

我最终发现你所要做的就是改变IL以使Add函数变为私有.

现在本着解耦代码的精神,我很可能会使用接口,但似乎并没有找到Concurrent字典的Add方法.

真正使用它是否安全Add(我无法查看IL,因此我不知道它是否真的是线程安全的.)?或者我应该使用具体类型ConcurrentDictionary<TKey, TValue>并明确使用TryAdd.

Eri*_*rik 8

是的,这很安全.

看看ConcurrentDictionary参考源.如果密钥已存在,则该方法IDictionary<TKey, TValue>.Add只调用TryAdd并抛出异常.

隐藏接口成员并不需要进行IL修改.它可以通过C#中的显式接口实现来完成.这是通过省略方法的访问修饰符并在方法名称前加上接口名称来完成的:

void IDictionary<TKey,TValue>.Add(TKey key, TValue value) {}
Run Code Online (Sandbox Code Playgroud)

这样做有很多原因,也许你不想混淆具体的界面,或者如果界面上的方法名称不够具体,你希望你的类的消费者明确他们使用的是什么方法.此外,它允许您为具有相同签名的不同接口上的方法提供单独的实现(对于ConcurrentDictionary我认为不是真正的问题,但如果您在自己的类中需要它,则可以使用该功能).

  • 我猜你可以这样说,"如果你知道你正在使用`ConcurrentDictionary`,你应该使用TryAdd"但是当通过界面访问时它仍然表现为`IDictionary`. (2认同)
  • 所以人们会明白,如果你使用具体的版本,你的代码应该是可读的并使用`TryAdd`,具体说明代码的作用. (2认同)

Han*_*ant 5

Hmya,你正在玩一个危险的游戏.ConcurrentDictionary类的公共接口提供了线程安全的方法,您可以在调用时感觉良好,知道它们表现良好.

但是Add()方法不是这样的方法,只有TryAdd()才是.您收到编译错误,因为Add()不是公共的,Microsoft 有意通过编写它的显式接口实现版本使该方法不可访问.否则他们必须做的事情,ConcurrentDictionary实现IDictionary.他们是否应该实现该接口是有争议的.但他们做到了桥上的水.

当然,您可以非常轻松地转换为访问Add().但是现在感觉良好的感觉开始在边缘发展.非常恰当的,他们实现Add()的唯一方法是在TryAdd()失败时抛出异常.带有ArgumentException的Kaboom,祝你好运调试.

当这样的基本操作失败时,您绝对100%确定可以处理工作线程上的异常吗?您是否考虑过在catch子句中需要做什么,而不是考虑攻击IL?如果你这样做,那么当TryAdd()返回false时,它与你编写的代码有什么不同?

它没有什么不同.