使用接口声明变量是一个好习惯吗?在我的公司,我们对它进行了讨论,我非常反对。
e.g。我想要一个存储字符串键和字符串值对的集合。我也不想允许重复。很明显,我在我的班级中声明了Dictionary变量,该变量将公开(通过属性)。
Dictionary<string, string> myDic;
然而,一名团队成员说这不是一个好习惯!他说你用IDictionary声明一个变量,这将允许消费者分配他们想要的任何集合(实现IDictionary)。例如哈希表或字典
IDictionary myDic;
myDic = new Hashtable(); // Consumer's code
OR
mydic = new Dictionary<string, string>(); // Consumer's code
-
我现在可以知道,将变量声明为接口类型真的是一个好习惯吗?当我清楚地知道该变量的预期时,那也是如此?
答案 0 :(得分:13)
对于局部变量,私有字段等,它只是分裂头发。使用接口类型定义公共属性是有好处的。例如,当我看到一个公开类型为List<string>
的属性的类时,我感到畏缩。
如果您正在使用依赖注入或像MEF这样的组合框架,那么强烈建议使用接口而不是具体实现。它使您可以轻松地将实现与测试实现交换。
答案 1 :(得分:6)
在您的公共界面上,您通常应尝试将尽可能抽象的类型公开,以便有效地满足用户的要求(即使您的“用户”是您自己的代码)。
您应该为这些泛型类型分配好的默认值,这样您就可以在代码中尽快开始使用它们,而不是每次要使用它时都必须创建和指定具体的类型。
一个例子:
public class Something
{
public Something()
{
this.Map = new Dictionary<string, string>();
}
public IDictionary<string, string> Map { get; set; }
}
这允许类或实现者的用户在不破坏现有代码的情况下切换到新的字典类型,但也不要求用户每次使用它时都要编写此代码:
var something = new Something();
something.Map = new Dictionary<string, string>();
他们可以开始使用它:
var something = new Something();
something.Map["test"] = "some value";
其他类型的示例:
public IEnumerable<string> ValuesReadOnly { get; private set; } // Read-only access
public IEnumerable<string> ValuesReadWrite { get; set; } // Sequence read-write access
public IList<string> ValuesRandomReadWrite { get; set; } // Random read-write access
这样做的一个很好的理由是,您可以在将来插入任何类型,而无需先将其转换为您定义的特定类型。没有什么比必须与各种类型进行转换更快地污染代码了。
例如,我发现在使用Linq时我经常使用IEnumerable
。如果我的公共成员有List<T>
,我必须在分配之前将值转换为列表,这不仅会使我的代码膨胀,还会损害性能。您必须在内存中创建列表结构的另一个副本,并且您无法利用延迟评估序列/ yield return
等内容。
这方面的一个例子:
public class Something2
{
public IEnumerable<string> 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<string> 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...
答案 2 :(得分:1)
字典myDic;
是私有类级变量,因此没有消费者可以修改它。
第二,如果你真的关心IDictionary而不是你可以创建一个Generic类#
Public Class MyClass&lt; T&GT;其中T:字典&lt; T键,T源&gt;
并定义MyClass的变量
答案 3 :(得分:1)
我个人更喜欢这样的东西:
var statesByPostalCode = states.ToDictionary(s => s.PostalCode);
通过使用var
,编译器/ IDE仍然可以告诉您它是什么,可用的方法等等。类型可以通过最小的努力从Dictionary更改为IDictionary:
var statesByPostalCode = GetStatesByPostalCode();
var myState = statesByPostalCode[myStateCode];
在上面的语句中,方法GetStatesByPostalCode()可能会返回一个Dictionary或IDictionary,或者其他一些提供基于字符串的索引器的集合,并且它的返回类型可能会在某个地方的某个其他文件中发生更改,而您不会改变这些代码行。同时,名称statesByPostalCode
表示此变量的真正含义:一个集合,您可以通过其邮政编码查找每个州。
答案 4 :(得分:1)
接口更好,但选择正确的接口是您示例中的主要问题。您不能使用IDictionary<string, string>
吗?