将接口用作私有成员类型是否有意义?

Does it make sense to use interfaces as type of private members?

当我在 C# 中编写 class 时,我经常不仅在 public API/signatures 中使用接口类型,而且还作为私有成员的类型:

public class Foo {
    private readonly IDictionary<string, Bar> m_Bars; // <-- here

    public Foo() {
        m_Bars = new Dictionary<string, Bar>();
    }
}

在某些情况下我不这样做,主要是在我需要公开可变集合的某些ReadOnly接口变体时。最常见的示例是 List<T> 我想公开为 IReadOnlyCollection<T>IReadOnlyList<T>;我不能使成员分别成为 ICollection<T> IList<T>,因为这些接口没有扩展它们的 IReadOnly 对应 and I'd have to 以使其工作:

public class Foo {
    private readonly List<Bar> m_Bars; // <-- not here

    public Foo() {
        m_Bars = new List<Bar>();
    }
    
    public IReadOnlyCollection<Bar> Bars => m_Bars;
}

受保护的实例成员有点介于私有成员和 public API 之间,因此公开接口而不是 classes 的一般好处确实适用。

但是对于私人会员,help/hurt/make有什么区别吗?例如,它是否在每次访问成员时引入额外的类型检查?

视情况而定。如果你在构造函数中创建它,你就知道它已经是什么类型了。当您使用依赖注入时,使用接口可能更有意义,因此您的 class 可以获得不同 class 的实例,并且您不必更改内部实现。在您使用 Dictionary 的情况下,我会保留特定类型主要是因为性能,您可以阅读更多内容 here

[does it make] sense to define a private member as IDictionary<K, V> instead of Dictionary<K, V> for example?

接口调用的开销很小,但它的数量级并不适合大多数场景。因此,让我们假设没有性能理由支持具体的 class 而不是接口。

使用more-derivedclass的好处是它有更丰富的API,例如

dictionary.Clear()

更简单,并且可能优于

var keysToRemove = dictionary.Keys.ToList();
foreach (var key in keysToRemove )
{
  dictionary.Remove(key);
}

dictonary = new Dictionary<TKey,TValue>();

使用界面的好处是以后切换到不同的 IDicionary 时,您永远不必更改代码。

对于fully-encapsulated私人会员来说,福利可能相当low-value。