I know there has been a lot of posts on this but it still confuses me why should you pass in an interface like IList and return an interface like IList back instead of the concrete list.
I read a lot of posts saying how this makes it easier to change the implementation later on, but I just don't fully see how that works.
Say if I have this method
public class SomeClass { public bool IsChecked { get; set; } } public void LogAllChecked(IList<SomeClass> someClasses) { foreach (var s in someClasses) { if (s.IsChecked) { // log } } }
I am not sure how using IList will help me out in the future.
How about if I am already in the method? Should I still be using IList?
public void LogAllChecked(IList<SomeClass> someClasses) { //why not List<string> myStrings = new List<string>() IList<string> myStrings = new List<string>(); foreach (var s in someClasses) { if (s.IsChecked) { myStrings.Add(s.IsChecked.ToString()); } } }
What do I get for using IList now?
public IList<int> onlySomeInts(IList<int> myInts) { IList<int> store = new List<int>(); foreach (var i in myInts) { if (i % 2 == 0) { store.Add(i); } } return store; }
How about now? Is there some new implementation of a list of int's that I will need to change out?
Basically, I need to see some actual code examples of how using IList would have solved some problem over just taking List into everything.
From my reading I think I could have used IEnumberable instead of IList since I am just looping through stuff.
Edit So I have been playing around with some of my methods on how to do this. I am still not sure about the return type(if I should make it more concrete or an interface).
public class CardFrmVm { public IList<TravelFeaturesVm> TravelFeaturesVm { get; set; } public IList<WarrantyFeaturesVm> WarrantyFeaturesVm { get; set; } public CardFrmVm() { WarrantyFeaturesVm = new List<WarrantyFeaturesVm>(); TravelFeaturesVm = new List<TravelFeaturesVm>(); } } public class WarrantyFeaturesVm : AvailableFeatureVm { } public class TravelFeaturesVm : AvailableFeatureVm { } public class AvailableFeatureVm { public Guid FeatureId { get; set; } public bool HasFeature { get; set; } public string Name { get; set; } } private IList<AvailableFeature> FillAvailableFeatures(IEnumerable<AvailableFeatureVm> avaliableFeaturesVm) { List<AvailableFeature> availableFeatures = new List<AvailableFeature>(); foreach (var f in avaliableFeaturesVm) { if (f.HasFeature) { // nhibernate call to Load<>() AvailableFeature availableFeature = featureService.LoadAvaliableFeatureById(f.FeatureId); availableFeatures.Add(availableFeature); } } return availableFeatures; }
Now I am returning IList for the simple fact that I will then add this to my domain model what has a property like this:
public virtual IList<AvailableFeature> AvailableFeatures { get; set; }
The above is an IList itself as this is what seems to be the standard to use with nhibernate. Otherwise I might have returned IEnumberable back but not sure. Still, I can't figure out what the user would 100% need(that's where returning a concrete has an advantage over).
Edit 2
I was also thinking what happens if I want to do pass by reference in my method?
private void FillAvailableFeatures(IEnumerable<AvailableFeatureVm> avaliableFeaturesVm, IList<AvailableFeature> toFill) { foreach (var f in avaliableFeaturesVm) { if (f.HasFeature) { // nhibernate call to Load<>() AvailableFeature availableFeature = featureService.LoadAvaliableFeatureById(f.FeatureId); toFill.Add(availableFeature); } } }
would I run into problems with this? Since could they not pass in an array(that has a fixed size)? Would it be better maybe for a concrete List?
The main difference between List and IList in C# is that List is a class that represents a list of objects which can be accessed by index while IList is an interface that represents a collection of objects which can be accessed by index.
Results. IList<T> uses 40 Bytes more than List<T> .
Generally best practice is to accept parameters of the most generic type and to return the most specific. However, conventionally programmers tend to not want to tie themselves to the List implementation and normally return the IList interface.
ICollection is one step ahead of IEnumerable. If we want some more functionality like Add or remove element, then it is better to go with ICollection because we cannot achieve that with IEnumerable. ICollection extends IEnumerable.
There are three questions here: what type should I use for a formal parameter? What should I use for a local variable? and what should I use for a return type?
The principle here is do not ask for more than you need. IEnumerable<T>
communicates "I need to get the elements of this sequence from beginning to end". IList<T>
communicates "I need to get and set the elements of this sequence in arbitrary order". List<T>
communicates "I need to get and set the elements of this sequence in arbitrary order and I only accept lists; I do not accept arrays."
By asking for more than you need, you (1) make the caller do unnecessary work to satisfy your unnecessary demands, and (2) communicate falsehoods to the reader. Ask only for what you're going to use. That way if the caller has a sequence, they don't need to call ToList on it to satisfy your demand.
Use whatever you want. It's your method. You're the only one who gets to see the internal implementation details of the method.
Same principle as before, reversed. Offer the bare minimum that your caller requires. If the caller only requires the ability to enumerate the sequence, only give them an IEnumerable<T>
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With