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

5

使用接口声明变量是一个好的实践吗?在我的公司,我们就此进行了讨论,我对此持反对态度。

例如,我想要一个存储字符串键和字符串值对的集合。我也不想允许重复。因此,我在我的类中明确声明了一个Dictionary变量,该变量将通过属性公开。

Dictionary<string, string> myDic;

然而,有一位团队成员表示这并不是一个好的做法!他认为应该使用IDictionary声明变量,这将允许消费者分配任何他们想要的集合(实现IDictionary),如Hashtable或Dictionary。

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

或者

mydic = new Dictionary<string, string>(); // 使用者的代码 -

我想知道,将变量声明为接口类型真的是一个好习惯吗?尤其是当我清楚地知道该变量所期望的类型时?


如果有一天微软用SuperDuperDictionary<>替换了Dictionary<>,那么使用你的类的任何人都无法利用它,你怎么办? - Yuriy Faktorovich
5个回答

13

对于局部变量、私有字段等,这只是琐碎的区分。但使用接口类型定义公共属性有好处。例如,当我看到一个公开类型为List<string>的属性时,我感到不安。

如果您正在使用依赖注入或像MEF这样的组合框架,则强烈建议使用接口而不是具体实现。它使您能够轻松地使用测试实现替换实现。


2
+1,因为对于本地/私有变量来说,这是无关紧要的。此外,我主张在不影响可读性/可理解性的情况下使用var,因为它可以进一步减少代码更改的影响 :) - Merlyn Morgan-Graham

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时经常使用。如果我的公共成员是,那么在分配值之前,我总是需要将值转换为列表,这不仅使我的代码变得臃肿,而且还会影响性能。您必须在内存中再次复制列表结构,并且无法利用懒惰评估序列/ 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...

1
我个人更喜欢这样的东西:
var statesByPostalCode = states.ToDictionary(s => s.PostalCode);

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

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

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

成员变量不起作用--接口还是具体类型? - user166390
你说得对。当我第一次读到这个问题时,我以为我们在谈论局部变量。对于公开的属性等,我会使用通用接口。 - StriplingWarrior

1

字典 myDic;

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

2. 如果您真的关心IDictionary,那么可以创建一个泛型类#

public class MyClass<T> where T : Dictionary <T Key, T Source>

然后定义MyClass的变量


1

接口更好,但在你的例子中选择正确的接口是主要问题。您是否可以改用IDictionary<string, string>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接