将变量声明为接口类型是一种好/可接受的做法吗?

使用接口声明变量是一个好习惯吗? 在我的公司,我们讨论过它,我反对它。

例如,我想要一个存储字符串键和字符串值对的集合。 我也不想允许重复。 很明显,我在我的class级中声明了Dictionary变量,这些变量将公开(通过属性)。

Dictionary myDic; 

但是,一个团队成员说这不是一个好习惯! 他说你用IDictionary声明一个变量,这将允许消费者分配他们想要的任何集合(实现IDictionary)。 例如Hashtable或Dictionary

 IDictionary myDic; myDic = new Hashtable(); // Consumer's code 

要么

mydic = new Dictionary(); // Consumer's code mydic = new Dictionary(); // Consumer's code

我现在可以知道,将变量声明为接口类型真的是一个好习惯吗? 当我清楚地知道该变量的预期时,那也是如此?

对于局部变量,私有字段等,它只是分裂头发。 使用接口类型定义公共属性是有好处的。 例如,当我看到一个暴露类型为List的属性的类时,我感到畏缩。

如果您正在使用dependency injection或像MEF这样的combobox架,那么强烈建议使用接口而不是具体实现。 它使您可以轻松地将实现与测试实现交换。

在您的公共接口上,您通常应尝试将尽可能抽象的类型公开,以有效地满足用户的要求(即使您的“用户”是您自己的代码)。

您应该为这些generics类型分配好的默认值,这样您就可以在代码中尽快开始使用它们,而不是每次要使用它时都必须创建和分配具体类型。

一个例子:

 public class Something { public Something() { this.Map = new Dictionary(); } public IDictionary Map { get; set; } } 

这允许类或实现者的用户在不破坏现有代码的情况下切换到新的字典类型,但也不要求用户每次使用它时都要编写此代码:

 var something = new Something(); something.Map = new Dictionary(); 

他们可以开始使用它:

 var something = new Something(); something.Map["test"] = "some value"; 

其他类型的示例:

 public IEnumerable ValuesReadOnly { get; private set; } // Read-only access public IEnumerable ValuesReadWrite { get; set; } // Sequence read-write access public IList ValuesRandomReadWrite { get; set; } // Random read-write access 

这样做的一个很好的理由是,您可以在将来插入任何类型,而无需先将其转换为您定义的特定类型。 没有什么比必须与各种类型进行转换更快地污染代码。

例如,我发现在使用Linq时我IEnumerable使用IEnumerable 。 如果我的公共成员有List ,我总是必须在分配之前将值转换为列表,这不仅会使我的代码膨胀,还会损害性能。 您必须在内存中创建列表结构的另一个副本,并且您无法利用惰性计算序列/ yield return

一个例子:

 public class Something2 { public IEnumerable SomeValues { get; set; } } var dbQuery = BuildQuery("select item from inventory where item.Price > 5.00"); var something = new Something(); something.SomeValues = dbQuery.Evaluate(); // Imagine if this did paging... 

代替:

 public class Something2 { public List SomeValues { get; set; } } var dbQuery = BuildQuery("select item from inventory where item.Price > 5.00"); var something = new Something(); something.SomeValues = dbQuery.Evaluate().ToList(); // Has to evaluate all of them... 

字典myDic;

是私有类级变量,因此没有消费者可以修改它。

如果你真的关心IDictionary而不是你可以创建一个Generic类#2

Public Class MyClass 其中T:Dictionary

而不是定义MyClass的变量

接口更好,但选择正确的接口是您的示例中的主要问题。 您不能使用IDictionary吗?

我个人更喜欢这样的东西:

 var statesByPostalCode = states.ToDictionary(s => s.PostalCode); 

通过使用var ,编译器/ IDE仍然可以告诉您它是什么,可用的方法等等。类型可以通过最小的努力从Dictionary更改为IDictionary:

 var statesByPostalCode = GetStatesByPostalCode(); var myState = statesByPostalCode[myStateCode]; 

在上面的语句中,方法GetStatesByPostalCode()可能会返回一个Dictionary或IDictionary,或者其他一些提供基于字符串的索引器的集合,并且它的返回类型可能会在某个地方的某个其他文件中更改,而您不必更改这些代码行。 同时,名称statesByPostalCode表示该变量真正具有的内容:一个集合,您可以通过其邮政代码查找每个州。