Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it a good/acceptable practice to declare variable as interface type?

Tags:

c#

Is it a good practice to declare variable using the interface? In my company we had a discussion on it and I'm quite against it.

e.g. I wanted to have a collection storing string keys and string value pairs. I don't want to allow duplicates either. So clearly I declared Dictionary variable in my class which would be exposed publicly (via property).

Dictionary<string, string> myDic;

However, a team member says that it's not a good practice ! He is saying that you declare a variable with IDictionary and this will allow consumers to assign any collection (implementing IDictionary) which they want. e.g. Hashtable or Dictionary

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

OR

mydic = new Dictionary<string, string>(); // Consumer's code -

May I know now, is it really a good practice to declare variable as type of interface? And that too when I clearly know what is expected from that variable?

like image 595
Learner Avatar asked Dec 16 '10 04:12

Learner


2 Answers

For local variables, private fields, etc it's just splitting hairs. There is a benefit to defining public properties using an interface type. For example, I cringe when I see a class that exposes a property of type List<string>.

If you're using dependency injection or a composition framework like MEF then using interfaces instead of concrete implementations is highly recommended. It enables you to easily swap out implementations with test implementations.

like image 120
Josh Avatar answered Nov 04 '22 17:11

Josh


On your public interface, you should generally try to expose as abstract a type as possible that usefully fulfills your user's requirements (even if your "user" is your own code).

You should assign good defaults for these generic types, so you can start using them ASAP in your code, rather than having to create and assign a concrete type each time you want to use it.

An example:

public class Something
{
  public Something()
  {
    this.Map = new Dictionary<string, string>();
  }

  public IDictionary<string, string> Map { get; set; }
}

This allows the user of the class, or the implementor, to switch to a new dictionary type without breaking existing code, yet also doesn't require the user to write this code every time they use it:

var something = new Something();
something.Map = new Dictionary<string, string>();

They can just start using it:

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

Examples for other types:

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

One good reason to do this is so that you can plug in any type in the future, without first having to convert it to the specific type you defined. Nothing pollutes code faster than having to do conversions to and from various types.

For example, I find I use IEnumerable a lot when using Linq. If I had List<T> for my public members, I'd always have to convert values to lists before I assigned them, which not only bloats my code, but also hurts performance. You have to make another copy of the list structure in memory, and you can't take advantage of stuff like lazy evaluated sequences/yield return.

An example of this:

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

Instead of:

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...
like image 36
Merlyn Morgan-Graham Avatar answered Nov 04 '22 16:11

Merlyn Morgan-Graham