93

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:

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).

My question is: are there any merits to his way of doing things? Is this a common practice in Java?

rein
  • 32,967
  • 23
  • 82
  • 106
  • 13
    For local variables there really is no point. – Joren Oct 20 '09 at 15:49
  • Dupe: http://stackoverflow.com/questions/1484445/why-are-variables-declared-with-their-interface-name-in-java – Mehrdad Afshari Oct 20 '09 at 17:33
  • 7
    A good practice **BUT** beware of the performance cost: http://www.nimaara.com/2016/03/06/beware-of-the-idictionary-tkey-tvalue/ – MaYaN Mar 06 '16 at 18:39
  • 1
    The two major implementations of `IDictionary` (`Dictionary` and `ConcurrentDictionary`) have very different performance characteristics (e.g. `Count` is very fast on the former and very slow on the latter). _As such, my recommendation would be to specify the concrete class (rather than `IDictionary`) in C#, where possible, so that the consumer knows how to use the dictionary in a performant way._ – mjwills Sep 18 '17 at 07:25
  • 1
    Additionally, `IDictionary` has some performance 'quirks' - http://www.nimaara.com/2016/03/06/beware-of-the-idictionary-tkey-tvalue/ . – mjwills Jan 03 '19 at 11:11

14 Answers14

83

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

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.

Chris
  • 1,826
  • 12
  • 15
  • 27
    +1, but you might want to use the word 'general' rather than 'generic', which already has a bucketload of meaning attached :) – AakashM Oct 20 '09 at 15:49
  • "... often considered better ..." Where and why? If I use a LinkedList I want to use features of it that List doesn't provide. Besides the annoying casts, it is then not easily replaceable in the end. – The incredible Jan Mar 06 '23 at 10:29
29

This practice isn't just limited to 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.

You'll also see this practice used heavily with dealing with IoC containers and instanciation using the Factory pattern.

Justin Niessner
  • 242,243
  • 40
  • 408
  • 536
  • 2
    But you lose out on all the functionality that Dictionary might provide which is not in IDictionary. – rein Oct 20 '09 at 15:37
  • 10
    But if you're able to use IDictionary instead...you're not using the functionality to begin with. – Justin Niessner Oct 20 '09 at 15:38
  • 1
    But if you only need the functionality in IDictionary... It is easier to change IDictionary to Dictionary than the other way around :) – Svish Oct 20 '09 at 15:38
  • 1
    It's easier to cast a Dictionary to an IDictionary than the other way round. :) – rein Oct 20 '09 at 15:40
  • 11
    Losing the functionality that Dictionary provides but IDictionary doesn't is the whole point of this idiom. Declaring your local variable as IDictionary forces you to restrict your use of that variable to what is available via the interface. Then, if you later discover you must use some other class that implements IDictionay instead of Dictionary, you can do so by changing the one line that calls the concrete classes constructor (since you know your code only uses it as an IDictionary, not a Dictionary). – Stephen C. Steel Oct 20 '09 at 17:33
  • This is the perversion of object orientation. It probably is best not to use any classes other than Object. You can't get more general and interchangeable than that. – The incredible Jan Mar 06 '23 at 10:35
17

Your friend is following the very useful principle:

"Abstract yourself from implementation details"

Jeff B
  • 8,572
  • 17
  • 61
  • 140
Vitaliy Liptchinsky
  • 5,221
  • 2
  • 18
  • 25
10

For local variables and private fields, which are already implementation details, it's better to use concrete types than interfaces for the declarations because the concrete classes offer a performance boost (direct dispatch is faster than virtual/interface dispatch). The JIT will also be able to more easily inline methods if you don't unnecessarily cast to interface types in the local implementation details. If an instance of a concrete type is returned from a method that returns an interface, the cast is automatic.

Sam Harwell
  • 97,721
  • 20
  • 209
  • 280
  • 4
    That is a micro-optimization that should only be performed if you have a specific performance bottleneck to solve, it should not drive design. – Yishai Oct 20 '09 at 18:40
  • 9
    It's not a micro-optimization. You're already in the implementation where you've chosen a concrete implementation. Why pretend you haven't at the expense of performance? – Sam Harwell Oct 21 '09 at 13:41
8

You should always attempt to program to the interface rather than the concrete class.

In Java or any other object oriented programming language.

In .NET world is common to use an I to indicate that is an interface what your're using. I think this is more common because in C# they don't have implements and extends to refer class vs interface inheritance.

I think whey would type

 class MyClass:ISome,Other,IMore 
 { 
 }

And you can tell ISome an IMore are interfaces while Other is a class

In Java there is no need for such a thing

 class MyClass extends Other implements Some, More {
 }

The concept still applies, you should try to code to the interface.

OscarRyz
  • 196,001
  • 113
  • 385
  • 569
  • 4
    I don't think his question was about how interfaces or work or why they start with I. Furthermore, base classes have to be declared before interfaces. So, `public class MyClass : BaseClass, IFirstInterface, ISecondInterface` would be correct. There's nothing inherently special about I at the beginning of an interface. The compiler doesn't treat it differently. It's a marker for other programmers. You could name your interfaces without them . . . but other programmers would likely hate you. – tandrewnichols Dec 26 '12 at 23:03
7

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.

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.

Travis Heseman
  • 11,359
  • 8
  • 37
  • 46
6

IDictionary is an interface and Dictionary is a class.

Dictionary implements IDictionary.

That means that this is possible to refer to Dictionary instance with/by IDictionary instance and invoke most of the Dictionary methods and properties through IDictionary instance.

This is very recommended to use interfaces as many as possible, because interfaces abstracts the modules and assemblies of the applications, allows polymorphism, which is both very common and useful in many situations and cases and allows replacing one module by another without touching the other modules.

Suppose that in the present, the programmer wrote:

IDictionary<string> dictionary = new Dictionary<string>();

And now dictionary invokes the methods and properties of Dictionary<string>.

In the future the databases has been grown up in size and we find out that Dictionary<string> is too slow, so we want to replace Dictionary<string> by RedBlackTree<string>, which is faster.

So all what is needed to be done is replacing the above instruction to:

IDictionary<string> dictionary = new RedBlackTree<string>();

Of course that if RedBlackTree implements IDictionary then all the code of the application compiles successfully and you have a newer version of your application, where the application now performs faster and more efficient than the previous version.

Without interfaces, this replacement would be more difficult to do and would require the programmers and developers to change more code that is potential to bugs.

user11336341
  • 95
  • 1
  • 3
5

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?

Gergely Orosz
  • 6,475
  • 4
  • 47
  • 59
  • 1
    I was with you until the second sentence. How else are you supposed to acquire a reference to an interface implementer? You have to instantiate something that implements it. `new IDictionary()` wouldn't work, and makes no sense anyway. – Tom W Jul 12 '11 at 17:32
  • I don't really understand... my point was that who ever uses the dictionary member will only want to use IDictionary capabilities. Obviously you have to instantiate something but if you use this pattern the following codes will mean the same for who ever uses the class: IDictionary dictionary = new Dictionary(); and IDictionary dictionary = new ConcurrentDictionary(); If you won't be using Dictionary or ConcreteDictionary specific members, it makes sense not to declare them as the type of the class variable, adding a layer of abstraction. – Gergely Orosz Jul 13 '11 at 08:28
  • "who ever uses the dictionary member will only want to use IDictionary capabilities" doem't make any sense. – The incredible Jan Mar 06 '23 at 10:40
3

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:

Map map = new HashMap();
List list = new ArrayList();

Guess it just accomplishes loose coupling in a lot of situations.

NickDK
  • 5,159
  • 2
  • 18
  • 11
3

Java Collections include a multitude of implementations. Therefore, it's much easier for me to make use of

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

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.

Edit:

Failed to hit on one of my key points (just alluded to it with the getter/setters).

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.

MarkPowell
  • 16,482
  • 7
  • 61
  • 77
  • 1
    changing that line to: Vector myList = new Vector(); is also only changing one line. – tster Oct 20 '09 at 16:00
  • 1
    @tster - but what other code calls methods that are specific to ArrayList that would have to be changed because Vector doesn't have the exact same method? – Gordon Tucker Oct 20 '09 at 16:34
  • public void setMyList(List list) { myList = list; } Is valid, when declaring it as a List, not so when using a direct implementation. I.e. a client can use whatever list they may have without worrying about converting to your implementation. – MarkPowell Oct 20 '09 at 17:17
  • @Gordon Tucker It is nonsense to instantiate an ArrayList if you do not want to use any specific functions/properties of it. – The incredible Jan Mar 06 '23 at 10:44
3

Coming from a Java world, I agree that the "program to an interface" mantra is drilled into you. By programming to an interface, not an implementation, you make your methods more extensible to future needs.

Anjisan
  • 1,789
  • 3
  • 15
  • 26
1

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).

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.

LBushkin
  • 129,300
  • 32
  • 216
  • 265
  • 2
    This was my opinion too - for method definitions it's more important to try and use the general type since the method can be reused. For local variables I don't see the merit. – rein Oct 20 '09 at 15:52
  • 1
    Personally I think the merit is the fact you will spot possible dependencies on implementation classes very easily. Like for example if you pass your local variable to a utility method or something. – NickDK Oct 20 '09 at 15:57
  • 2
    For local variables, the arguments I've seen are that 1) it keeps you disciplined in using interfaces, and 2) it allows your code to be less sensitive to the return types of function calls that assign to locals - meaning that the function can change the concrete type without impacting your code (so long as the return type still adheres to the interface, of course). – LBushkin Oct 20 '09 at 17:20
  • 1
    @LBushkin, I also find that as you are developing a method, and you do refactorings like extract method and the like, the concrete type can tend to propagate even though the interface should have been used. – Yishai Oct 20 '09 at 18:36
1

Using interfaces means that "dictionary" in the following code might be any implementation of 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(...);
Manrico Corazzi
  • 11,299
  • 10
  • 48
  • 62
  • I would agree that when using a factory to return a non-specific dictionary this is a good idea. – rein Oct 20 '09 at 15:39
  • 1
    What I meant was that using the interface forces you to think in "generic" terms, enforcing the decoupling of the classes (in my example the method using Dictionary1 has to be familiar with the inner structure of the class, not with the interface) – Manrico Corazzi Oct 21 '09 at 07:57
1

I've encountered the same situation with a Java developer. He instantiates collections AND objects to their interface in the same way. For instance,

IAccount account = new Account();

Properties are always get/set as interfaces. This causes problems with serialization, which is explained very well here

Community
  • 1
  • 1
Joseph Yaduvanshi
  • 20,241
  • 5
  • 61
  • 69
  • 1
    This is only a problem with the "magic" serialization that .NET uses on web service interfaces. The practice of using interfaces instead of concrete classes is perfectly sound. – Daniel Pryden Oct 20 '09 at 17:13
  • We've had the problem specifically with ViewState serialization in ASP.NET 1.1 – Joseph Yaduvanshi Oct 20 '09 at 17:31