C# 风格差异:IDictionary vs Dictionary
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1595498/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
A difference in style: IDictionary vs Dictionary
提问by rein
I have a friend who's just getting into .NET development after developing in Java for ages and, after looking at some of his code I notice that he's doing the following quite often:
我有一个朋友,他在用 Java 开发多年后才进入 .NET 开发,在查看了他的一些代码后,我注意到他经常做以下事情:
IDictionary<string, MyClass> dictionary = new Dictionary<string, MyClass>();
He's declaring dictionary as the Interface rather than the Class. Typically I would do the following:
他将字典声明为接口而不是类。通常,我会执行以下操作:
Dictionary<string, MyClass> dictionary = new Dictionary<string, MyClass>();
I'd only use the IDictionary interface when it's needed (say, for example to pass the dictionary to a method that accepts an IDictionary interface).
我只会在需要时使用 IDictionary 接口(例如,将字典传递给接受 IDictionary 接口的方法)。
My question is: are there any merits to his way of doing things? Is this a common practice in Java?
我的问题是:他的做事方式有什么优点吗?这是Java中的常见做法吗?
采纳答案by Chris
If IDictionary is a "more generic" type than Dictionary then it makes sense to use the more generic type in declaring variables. That way you don't have to care as much about the implementing class assigned to the variable and you can change the type easily in the future without having to change a lot of following code. For example, in Java it's often considered better to do
如果 IDictionary 是比 Dictionary 更“通用”的类型,那么在声明变量时使用更通用的类型是有意义的。这样您就不必太关心分配给变量的实现类,并且您可以在将来轻松更改类型而无需更改大量以下代码。例如,在 Java 中,通常认为这样做更好
List<Integer> intList=new LinkedList<Integer>();
than it is to do
比做
LinkedList<Integer> intList=new LinkedList<Integer>();
That way I'm sure all following code treats the list as a List and not a LinkedList, making it easy in the future to switch out LinkedList for Vector or any other class which implements List. I'd say this is common to Java and good programming in general.
这样,我确信以下所有代码都将列表视为列表而不是 LinkedList,以便将来轻松切换 Vector 或任何其他实现 List 的类的 LinkedList。我会说这对于 Java 和一般的良好编程很常见。
回答by Justin Niessner
This practice isn't just limited to Java.
这种做法不仅限于 Java。
It's often used in .NET as well when you want to de-couple the instance of the object from the class you're using. If you use the Interface rather than the Class, you can change the backing type whenever needed without breaking the rest of your code.
当您想将对象的实例与您正在使用的类分离时,它也经常用于 .NET 中。如果您使用接口而不是类,您可以在需要时更改支持类型,而不会破坏其余代码。
You'll also see this practice used heavily with dealing with IoC containers and instanciation using the Factory pattern.
您还将看到这种做法在处理 IoC 容器和使用工厂模式的实例化时被大量使用。
回答by Gergely Orosz
As far as I've seen Java developers tend to use abstraction (and design patterns) more often than .NET developers. This seems another example of it: why declare the concrete class when he'll essentially only be working with the interface members?
据我所知,Java 开发人员比 .NET 开发人员更倾向于使用抽象(和设计模式)。这似乎是另一个例子:当他基本上只与接口成员一起工作时,为什么要声明具体类?
回答by LBushkin
I've found that for local variables it generally doesn't much matter whether you use the interface or the concrete class.
我发现对于局部变量,使用接口还是具体类通常并不重要。
Unlike class members or method signatures, there is very little refactoring effort if you decide to change types, nor is the variable visible outside its usage site. In fact, when you use var
to declare locals, you are not getting the interface type but rather the class type (unless you explicitly cast to the interface).
与类成员或方法签名不同,如果您决定更改类型,则重构工作很少,变量在其使用站点之外也不可见。事实上,当您使用var
声明局部变量时,您获得的不是接口类型而是类类型(除非您显式转换为接口)。
However, when declaring methods, class members, or interfaces, I think that it will save you quite a bit of headache to use the interface type up front, rather than coupling the public API to a specific class type.
但是,在声明方法、类成员或接口时,我认为预先使用接口类型而不是将公共 API 耦合到特定类类型会为您省去不少麻烦。
回答by Manrico Corazzi
Using interfaces means that "dictionary" in the following code might be any implementation of IDictionary.
使用接口意味着以下代码中的“字典”可能是 IDictionary 的任何实现。
Dictionary1 dictionary = new Dictionary1();
dictionary.operation1(); // if operation1 is implemented only in Dictionary1() this will fail for every other implementation
It's best seen when you hide the construction of the object:
当您隐藏对象的构造时,最好看到:
IDictionary dictionary = DictionaryFactory.getDictionary(...);
回答by Vitaliy Liptchinsky
Your friend is following the very useful principle:
你的朋友正在遵循一个非常有用的原则:
"Abstract yourself from implementation details"
“从实现细节中抽象出来”
回答by NickDK
In the described situation almost every Java developer would use the interface to declare the variable. The way the Java collections are used is probably one of the best examples:
在所描述的情况下,几乎每个 Java 开发人员都会使用接口来声明变量。Java 集合的使用方式可能是最好的例子之一:
Map map = new HashMap();
List list = new ArrayList();
Guess it just accomplishes loose coupling in a lot of situations.
猜猜它只是在很多情况下实现了松耦合。
回答by MarkPowell
Java Collections include a multitude of implementations. Therefore, it's much easier for me to make use of
Java 集合包括多种实现。因此,我更容易使用
List<String> myList = new ArrayList<String>();
Then in the future when I realize I need "myList" to be thread safe to simply change this single line to
然后在将来当我意识到我需要“myList”是线程安全的时,只需将这一行更改为
List<String> myList = new Vector<String>();
And change no other line of code. This includes getters/setters as well. If you look at the number of implementations of Map for example, you can imagine why this might be good practice. In other languages, where there is only a couple implementations for something (sorry, not a big .NET guy) but in Objective-C there is really only NSDictionary and NSMutableDictionary. So, it doesn't make as much sense.
并且不更改其他代码行。这也包括 getter/setter。例如,如果您查看 Map 的实现数量,您可以想象为什么这可能是一种很好的做法。在其他语言中,某些东西只有几个实现(抱歉,不是一个大的 .NET 人),但在 Objective-C 中,实际上只有 NSDictionary 和 NSMutableDictionary。所以,它没有多大意义。
Edit:
编辑:
Failed to hit on one of my key points (just alluded to it with the getter/setters).
未能找到我的一个关键点(只是用 getter/setter 提到它)。
The above allows you to have:
以上允许您拥有:
public void setMyList(List<String> myList) {
this.myList = myList;
}
And the client using this call need not worry about the underlying implementation. Using whatever object that conforms to the List interface that they may have.
并且使用此调用的客户端无需担心底层实现。使用符合他们可能拥有的 List 接口的任何对象。
回答by Jim Schubert
I've encountered the same situation with a Java developer. He instantiates collections AND objects to their interface in the same way. For instance,
我遇到过与 Java 开发人员相同的情况。他以相同的方式将集合和对象实例化到它们的接口。例如,
IAccount account = new Account();
Properties are always get/set as interfaces. This causes problems with serialization, which is explained very well here
属性总是作为接口获取/设置。这会导致序列化出现问题,这里解释得很好
回答by Travis Heseman
Most often, you see the interface type (IDictionary) used when the member is exposed to external code, whether that be outside the assembly or just outside the class. Typically, most developers use the concrete type internally to a class definition while they expose an encapsulated property using the interface type. In this way, they can leverage the concrete type's capabilities, but if they change the concrete type, the declaring class's interface doesn't need to change.
大多数情况下,您会看到当成员暴露给外部代码时使用的接口类型 (IDictionary),无论是在程序集之外还是在类之外。通常,大多数开发人员在类定义内部使用具体类型,同时使用接口类型公开封装的属性。通过这种方式,他们可以利用具体类型的能力,但是如果他们改变了具体类型,则声明类的接口不需要改变。
public class Widget { private Dictionary<string, string> map = new Dictionary<string, string>(); public IDictionary<string, string> Map { get { return map; } } }
later can become:
后来可以变成:
class SpecialMap<TKey, TValue> : IDictionary<TKey, TValue> { ... } public class Widget { private SpecialMap<string, string> map = new SpecialMap<string, string>(); public IDictionary<string, string> Map { get { return map; } } }
without changing Widget's interface and having to change other code already using it.
无需更改 Widget 的界面,也不必更改已经使用它的其他代码。