Question: Have I got this example backwards?
Is the reason to return Interface so that:
Try1:
public class Thing
{
public string name { get; set; }
public int age { get; set; }
public IList<Thing> giveMeAllThings()
{
IList<Thing> listOfThings = new List<Thing>();
Thing thing1 = new Thing { name = "phone", age = 3 };
Thing thing2 = new Thing { name = "waterbottle", age = 2 };
Thing thing3 = new Thing { name = "pinecone", age = 17 };
listOfThings.Add(thing1);
listOfThings.Add(thing2);
listOfThings.Add(thing3);
return listOfThings;
}
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void UnitTestThings()
{
Thing thing = new Thing();
IEnumerable<Thing&开发者_如何学Pythongt; listOfThings = thing.giveMeAllThings();
Assert.AreEqual(3, listOfThings.Count()); // linq count
Assert.IsTrue(listOfThings.Any(t => t.name == "phone" && t.age == 3));
Assert.IsTrue(listOfThings.Any(t => t.name == "waterbottle" && t.age == 2));
Assert.IsTrue(listOfThings.Any(t => t.name == "pinecone" && t.age == 17));
}
}
try2. I figure out that as I only need IEnumerable then I can just return that.
public IEnumerable<Thing> giveMeAllThings()
{
IList<Thing> listOfThings = new List<Thing>();
Thing thing1 = new Thing { name = "phone", age = 3 };
Thing thing2 = new Thing { name = "waterbottle", age = 2 };
Thing thing3 = new Thing { name = "pinecone", age = 17 };
listOfThings.Add(thing1);
listOfThings.Add(thing2);
listOfThings.Add(thing3);
foreach (Thing t in listOfThings)
yield return t;
}
Edit: So if I need a List in one method but not another, then the most 'General' interface possible to return is an IList:
public IList<Thing> giveMeAllThings()
{
IList<Thing> listOfThings = new List<Thing>();
Thing thing1 = new Thing { name = "phone", age = 3 };
Thing thing2 = new Thing { name = "waterbottle", age = 2 };
Thing thing3 = new Thing { name = "pinecone", age = 17 };
listOfThings.Add(thing1);
listOfThings.Add(thing2);
listOfThings.Add(thing3);
return listOfThings;
}
[TestMethod]
public void UnitTestThings()
{
Thing thing = new Thing();
IEnumerable<Thing> listOfThings = thing.giveMeAllThings();
Assert.AreEqual(3, listOfThings.Count()); // linq count
}
[TestMethod]
public void UnitTestThingsWhereINeedAnActualList()
{
Thing thing = new Thing();
IList<Thing> listOfThings = thing.giveMeAllThings();
Assert.AreEqual(3, listOfThings.Count); // List count
}
Is the reason to return Interface so that:
The main reason to do this is that, by returning the most "general" purpose interface possible, you have more flexibility in changing your internal implementation to something "better" (ie: more efficient, simpler code, whatever the criteria may be) later, without breaking your public API.
For example, if you switch from IList<T>
to IEnumerable<T>
, you could switch your code around to use iterators (yield return
) instead of a collection. You may decide that a different collection (instead of List<T>
) works better in your code, and switch to it. If that second collection didn't implement IList<T>
, it would require you to change your public API.
Well, you could return ICollection<Thing>
which has .Count
, Thing[]
which has .Length
, or IEnumberable<Thing>
which has the linq extension method .Count()
. You don't necessarily need IList<Thing>
if you just want the count of elements.
Using interfaces or basic return types also shows intent as to how the return type is intended to be used.
I tend to use IEnumerable<T>
most of the time.
I consider using arrays (or IList<T>
) when indexing is required.
An IEnumerable is less specific than an IList. I try to return the least specific thing that will still work.
Supposing I were returning an IDictionary, there's the tempation to return:
IEnumerable<ICollection<KeyValuePair<Key, Value>>
But I think that doesn't accurately describe what is happening, even though it is less specific than:
IDictionary<Key, Value>
精彩评论