I have something like:
public interface IThing
{
string Id { get; }
}
public class Ball : IThing
{
public string Id { get; }
}
public class Car : IThing
{
public string Id { get; }
}
For my 3-4 functions I want to treat Ball and Car the same. I use the interface so I dont have to make overload methods (one for car, one for ball).
Finally, there is on function where I have different logic if its a Ball or a Car. I get a IEnumerable<IThings> and I want to cast it to either IEnumerable<Car> or IEnumerable<Ball> depending what it consists of. If it consists of a mix, I want it to fail. It has to be all cars or all balls.
I tried something like:
var things = (inputs is IEnumerable<Ball>) ? input.Locations.Cast<Ball>() : input.Locations.Cast<Car>()
But it doesn't like that. What is the recommended approach where I can have 1 variable?
Edit:
The reason why I wanted to get it into one variable is because I am sending it to an overloaded method. So I want to do this:
var things = (inputs is IEnumerable<Ball>) ? input.Locations.Cast<Ball>() : input.Locations.Cast<Car>()
for (var i = 0; i < numRequests; i++)
{
var thingsSet = things.Skip(i * 1000).Take(1000);
var results = callOverLoadedFunction(thingsSet);
}
Rather than this:
if (inputs is IEnumerable<Ball>)
{
var things = input.Locations.Cast<Ball>();
for (var i = 0; i < numRequests; i++)
{
var thingsSet = things.Skip(i * 1000).Take(1000);
var results = callOverLoadedFunction(thingsSet);
}
}
else
{
var things = input.Locations.Cast<Car>();
for (var i = 0; i < numRequests; i++)
{
var thingsSet = things.Skip(i * 1000).Take(1000);
var results = callOverLoadedFunction(thingsSet);
}
}
The problem in your attempt it this:
inputs is IEnumerable<Ball>
Because an IEnumerable<IThing> that only contains elements of type Ball is not the same type as IEnumerable<Ball>. You really have no choice but to enumerate through your collection to determine if every item matches the type you require. You could use .Cast<...>() and handle the InvalidCastException, but that's a little bit hacky. Another way would be to use OfType<...>:
var cars = inputs.OfType<Car>();
var balls = inputs.OfType<Ball>();
And now you can deal with them as you wish, for example:
if(balls.Any() && cars.Any())
{
//You're not allowed to have balls and cars together
throw new Exception(...);
}
However, you are really breaking the open/closed principle of SOLID here, it seems like you should consider at a higher level what you are trying to achieve.
You could do a convert method, but that would still break some principles, as you still have to place an if statement.
I am not sure, you are using interfaces the right way with what you want to achieve.
If you want a car to behave different from a ball in a specific situation, then the implementation in the car shall do something different than the implementation in the ball.
Do not try to tweak an interface from outside. The implementations have to do this.
Why not create a method DoMySpecialStuff in IThing and you just iterate over your enumerable in this one special method that just calls DoMySpecialStuff on all the elements?
That's the way you can avoid your if-statement.
I just saw your edit with your overloadedMethod
So it could work like this:
for (var i = 0; i < numRequests; i++)
{
var thingsSet = things.Skip(i * 1000).Take(1000);
var results = callOverLoadedFunction(thingsSet);
}
void OverLoadedFunction(IThing thing)
{
thing.DoSpecialStuff(); // This does different things in car/ball
}
You can separate balls and cars from each other using LINQ
IEnumerable<Ball> balls = things.OfType<Ball>();
IEnumerable<Car> cars = things.OfType<Car>();
If you want it to fail and like one line solutions try something like this
IEnumerable<Ball> balls = things.OfType<Ball>().Count() == things.Count() ? things.OfType<Ball>() : null; //or whatever you want
I decided to redo something I did some time ago: the retransformation of partially a enumerated IEnumerator<> to full IEnumerable<>. This solves a problem that I feel is important: you shouldn't enumerate twice "unknown" IEnumerable<> (for "unknown" I mean IEnumerable<> that you haven't built by hand in the same method but that are of unknown origin), because there is no guarantee that it can be done, and even if it can be done, you could cause the big work needed to generate the IEnumerable<> to be done twice.
public class RemainingIEnumerator<T> : IEnumerable<T>
{
public IEnumerable<T> Enumerable { get; set; }
public int Nulls { get; set; }
public T First { get; set; }
public IEnumerator<T> Enumerator { get; set; }
public IEnumerator<T> GetEnumerator()
{
var enumerator = Enumerator;
if (enumerator == null)
{
return Enumerable.GetEnumerator();
}
return GetEnumerableRemaining().GetEnumerator();
}
private IEnumerable<T> GetEnumerableRemaining()
{
var enumerator = Enumerator;
Enumerator = null;
int nulls = Nulls;
Nulls = 0;
T first = First;
First = default(T);
for (int i = 0; i < nulls; i++)
{
yield return default(T);
}
yield return first;
while (enumerator.MoveNext())
{
yield return enumerator.Current;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public static bool Is<T>(IEnumerable<T> enu, Type type, out IEnumerable<T> enu2)
{
IEnumerator<T> enumerator = null;
int nulls = 0;
try
{
enumerator = enu.GetEnumerator();
while (enumerator.MoveNext())
{
var current = enumerator.Current;
if (current == null)
{
nulls++;
continue;
}
enu2 = new RemainingIEnumerator<T>
{
Enumerable = enu,
Nulls = nulls,
First = current,
Enumerator = enumerator,
};
enumerator = null;
return current.GetType() == type;
}
// Only nulls case
enu2 = new T[nulls];
return false;
}
finally
{
if (enumerator != null)
{
enumerator.Dispose();
}
}
}
The Is<T>() function returns true if the first non-null element is of the type type. It returns a new IEnumerable<> that can be used and that, through "magic", reuses the IEnumerable<> that was passed to Is<> (in some way it restitches the optional initial nulls, the first found element and the unused remaining IEnumerator<>).
Example of use:
var enu1 = new object[] { null, new Dog(), new Cat(), new Dog() };
IEnumerable<object> enu2;
// From this line onward, you should use at least one enu2!
// It is the partially unwinded enu1 that has been rewinded through
// some magic :-)
bool isDog = Is(enu1, typeof(Dog), out enu2);
if (isDog)
{
// Note the use of enu2!
foreach (Dog dog in enu2.Cast<Dog>())
{
}
}
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
List<IThing> testCollection = new List<IThing>();
testCollection.Add(new Ball());
testCollection.Add(new Car());
try
{
if (testCollection[0] is Ball)
{
Console.WriteLine(testCollection.Cast<Ball>().Count().ToString());
}
else
{
Console.WriteLine(testCollection.Cast<Car>().Count().ToString());
}
}
catch(InvalidCastException ex)
{
Console.WriteLine("Mix isn't allowed!");
}
}
}
public interface IThing
{
string Id { get; set;}
}
public class Ball : IThing
{
public string Id { get;set; }
}
public class Car : IThing
{
public string Id { get;set; }
}
This code will throw an InvalidCastException at the call to Cast<Ball> as the Car object can't be cast to Ball. This should do what you wanted, if I'm not mistaken.
The code will only check the type of the first element, as the List shouldn't be mixed, it can be assumed that all the other objects in that List should have the same type, if not that's, in my opinion and from how the question was written, appropiate cause to throw an exception.
Remember that IEnumerable<> is covariant, that is, you can substitute IEnumerable<Derived> whenever an IEnumerable<Base> is needed.
If you have only pure containers of things, that is only things of the same kind are in a given container, then you should make that container (which will be passed as an IEnumerable at some point) of that specific type. For example a factory could produce a true list of cars, a List<car>, in code like IEnumerable<Thing> things = factory.produceList(ThingTypes.Car);. Like all types, IEnumerable<> objects retain their actual type information even when they get assigned to references of a more basic type. This type can be used to distinguish the actual type of the IEnumerable<> at run-time.
Perhaps some code is easier to understand. I create two IEnumerable<I>s with elements of two distinct types which both implement the same interface I. As I said, I can assign an IEnumerable<T> to an IEnumerable<I> as long as T implements I.
using System;
using System.Collections.Generic;
namespace ConsoleApplication34
{
interface I { };
class T1 : I { }
class T2 : I { }
class Program
{
// strongly typed arrays get assigned to base type IEnumerables.
static IEnumerable<I> i1 = new T1[] { new T1(), new T1() };
static IEnumerable<I> i2 = new T2[] { new T2(), new T2() };
static void Main(string[] args)
{
// Note: compile-time type of array elements is IEnumerable<I>!
IEnumerable<I>[] iEnumArr = new IEnumerable<I>[] { i1, i2 };
foreach (IEnumerable<I> ie in iEnumArr)
{
// ... but the run-time types of the IEnumerable objects
// are actually different.
Console.WriteLine("ienumerable is of T1: " + (ie is IEnumerable<T1>));
Console.WriteLine("ienumerable is of T2: " + (ie is IEnumerable<T2>));
}
}
}
}
The output is
ienumerable is of T1: True
ienumerable is of T2: False
ienumerable is of T1: False
ienumerable is of T2: True
Edit of the edit: I see that you are working with thingsSet which is a true IEnumerable<Thing>. True, then the type tests don't work any longer.
Edit: Your edit is a bit unclear to me, but I assume that your overloaded method has two (or n) versions, one for an IEnumerable<car> and one for an IEnumerable<ball>. In that case I would do everything which is independent on the concrete type of the Thing first, and then distinguish only for the part where it matters. For example:
for (var i = 0; i < numRequests; i++)
{
var thingsSet = things.Skip(i * 1000).Take(1000);
// I may see your problem: Now with thingsSet we have true
// Enumerables of Thing, and the tests below are always false.
// Hm.
var carSet = thingsSet as IEnumerable<car>;
var ballSet = thingsSet as IEnumerable<ball>;
bool results;
if(carSet != null ) { results = callOverLoadedFunction(carSet); }
else if(ballSet != null) { results = callOverLoadedFunction(ballSet); }
else { throw /*...*/}
}
This solution has a bit of a code smell; ideally the calling code whouldn't be concerned with the concrete type of things. One possibility is to leave the "branching" for the distinct types to the Things. Or if that isn't possible, provide a single callNonOverLoadedFunction(IEnumerable<Thing>) with then branches internally, invisible to the caller. These functions are probably closer to the Things implementation and "know" which different types of Things exist; your calling code does not, and does not want to know, from a maintenance perspective.
Related
I'm trying to refactor the below into a generic function; the code sample below works for me if type is a specified in the function declaration. However, it fails when I try to use T.
I get an IENumerable-like object containing generic objects back from an external application, and from this want to filter out those that are of the specific type in question.
For context, these are geometric features selected on screen by the user prior to the code running. I need to validate that the correct type of thing has been picked, and return those things in a clean list.
Initial code with defined type that works:
public static List<Point> GetSelectedPoints()
{
List<Point> tmp = new List<Point>();
Selection oSel = GetSelectionObject();
for (int i = 1; i <= oSel.Count; i++)
{
try
{
if (oSel.Item(i).Value is Point)
{
Point P = (Point)oSel.Item(i).Value;
tmp.Add(P);
}
}
catch
{
throw new Exception("An error occurred whilst retrieving the selection");
}
}
return tmp;
}
Here the attempt to use T:
static public List<T> GetThisTypeFromSelection<T>()
{
Selection osel = GetSelectionObject();
List<T> tmp= new List<T>();
for(int i = 1; i<=osel.Count ; i++)
{
if (osel.Item(i).Value is T)
{
T thing = (T)osel.Item(i).Value;
tmp.Add(tmp);
}
}
return tmp;
}
osel.Item(i).Value.GetType() returns a "System.__ComObject"... Which is not helpful.
The object model of the external application is such that everything is derived from a single base class, with many layers of subclassing, something like this:
public class Base
{}
public class Geometry2d : Base
{ }
public class Line : Geometry2d
{ }
public class Circle : Line
{ }
public class Face : Geometry2d
{ }
public class PlanarFace : Face
{ }
public class CylindricalFace : Face
{ }
public class PlanarFaceDefinedThroughX : PlanarFace
{ }
public class PlanarFaceDefinedThroughY : PlanarFace
{ }
etcetera...
So, The selection object (while also deriving from base) returns a list of base object which could be...pretty much anything.
Depending on the application for this function, I might want to get, for example, everything that's a "Face" or derivative, or maybe just the PlanarFaces, or maybe even just the PlanarFaceDefinedThroughXs.
Update based on comments (kudos to mm8 pointing in the right direction)
static public List<T> GetThisTypeFromSelection<T>()
{
Selection osel = GetSelectionObject();
List<Base> listA = new List<Base>();
for(int i = 1; i<=osel.Count ; i++)
{
CATBaseDispatch CbD = osel.Item(i).Value;
listA.Add(CbD);
}
List<T> results = listA.Select(x => x).OfType<T>().ToList();
return results;
}
This approach seems to successfully filter out the right object types - but the returned list still shows them as COM objects...
If your Selection implements IEnumerable you could use Linq's OfType to filter items of desired type.
I am using CompareNetObjects for automated testing of my system. This has been useful in ensuring performance optimizations do not change the expected behavior of the system, and ensuring errors are not introduced.
When I have a collection that is declared in an abstract way, I expect to have the contents compared, not the collection itself; however, I do not see an option to enable this.
Class:
public class MustBeCorrect
{
public string Name { get; set; }
IEnumerable<string> Items { get; set; }
}
Test:
[Fact] void IsCorrect()
{
var obj1 = new MustBeCorrect
{
Name = "Kitty",
Items = new string[]
{
"Collar",
"Bell"
}
};
var obj2 = new MustBeCorrect
{
Name = "Kitty",
Items = new List<string>
{
"Collar",
"Bell"
}
};
comparer.Compare(obj1, obj2); // False!
}
The above two objects compare as not equal, even though the only difference between the two objects is one uses an array, and the other uses a list. In terms of my contract, however, these two seem as they should be considered equal to me.
How can I configure the comparison options to only compare the contents of collections, rather than the collection itself?
There does not exist a way to do what you want specifically for collections.
However, there is an option you can set called IgnoreObjectTypes in the ComparisonConfig. It is default to false, but if you set it to true, it should give you the behavior you desire for your collections.
Be aware, this will ignore object types for all comparisons.
This is the only way I found to make it work so far.
My solution consists in implementing a Custom comparer that ignores the generic argument of the collection when comparing IEnumerables.
However, the drawback of this approach is that you lose the granularity of the returned result.Differences: if two lists have different elements, it won't tell you exactly how and which elements are different.
If someone could identify a way to implement this in the Custom Comparer, that'd be great.
public class OnlyIEnumContents : BaseTypeComparer
{
public OnlyIEnumContents(RootComparer rootComparer) : base(rootComparer)
{
}
public OnlyIEnumContents() : this(RootComparerFactory.GetRootComparer())
{
}
public override bool IsTypeMatch(Type type1, Type type2)
{
if (typeof(IEnumerable).IsAssignableFrom(type1) && typeof(IEnumerable).IsAssignableFrom(type2))
return true;
return type1 == type2;
}
public override void CompareType(CompareParms parms)
{
var ienum1 = parms.Object1 as IEnumerable;
var ienum2 = parms.Object2 as IEnumerable;
if (ienum1 != null && ienum2 != null)
{
List<object> list1 = new List<object>();
List<object> list2 = new List<object>();
foreach (var item in ienum1)
list1.Add(item);
foreach (var item in ienum2)
list2.Add(item);
// Compare the lists.
// Because all the list elements were boxed in a System.Object,
// this only returns the differences between the single elements.
CompareLogic compareLogic = new CompareLogic();
ComparisonResult result = compareLogic.Compare(list1, list2);
// This is where granularity is lost.
// The official documentation https://github.com/GregFinzer/Compare-Net-Objects/wiki/Custom-Comparers
// points that we should return `AddDifference(parms)`,
// however I don't know how to get `parms` from a given `result` object.
// Returning a single difference for the entire lists.
if (!result.AreEqual)
AddDifference(parms);
}
}
}
And then to use it:
CompareLogic compareLogic = new CompareLogic();
compareLogic.Config.CustomComparers.Add(new OnlyIEnumContents());
ComparisonResult result = compareLogic.Compare(obj1, obj2);
Is there a way to remember the position of an enumerator?
I want to remember the position of an enumerate, so that I can reset it to a position before the current. I don't want to go back to the beginning so .reset() doesn't help.
Btw, is it possible to let the enumerator start eg at the 2. position?
List<string> list = new List<string>(new string[] { "a", "b", "c" });
IEnumerator<string> i = list.GetEnumerator();
i.MoveNext(); richTextBoxOutput.AppendText(i.Current);
IEnumerator<string> t = i; // how do I make a real copy i?
i.MoveNext(); richTextBoxOutput.AppendText(i.Current);
i = t;
i.MoveNext(); richTextBoxOutput.AppendText(i.Current);
As you already have a List<> why don't you maintain an indexer/counter then use the IEnumerable Skip() extension method (and possibly combine that with Take() followed by ForEach()).
Some possibly useful further info:
MSDN: Return Or Skip Elements in a Sequence
Stack Overflow: LINQ with Skip and Take
Is there a way to remember the position of an enumerator?
Sometimes. It depends on how the enumerator is implemented.
In this case the enumerator is implemented as a mutable struct, which was a performance optimisation that people more often run into when it produces this "freeze position" behaviour in situations where they don't want it. (If you're ever writing a generic class that wraps an implementation of IEnumerable<T> then either hold that reference as the interface type rather than the type itself, or don't have it readonly even if it seems like it should be, if you do you can end up with such a struct enumerator permanently frozen).
Just change your code so that instead of:
IEnumerator<string> i = list.GetEnumerator();
…
IEnumerator<string> t = i;
You have either:
List<string>.Enumerator i = list.GetEnumerator();
…
List<string>.Enumerator t = i;
Or simply:
var i = list.GetEnumerator();
…
var t = i;
Now you have i and t defined in terms of this struct and copying from one to the other copies the struct rather than just the reference to the boxed struct.
This will not work with all enumerators, and for that matter it isn't the best way to deliberately make it available when writing your own enumerator (if you needed to do so you'd be better adding some sort of Clone() or Snapshot() method to an enumerator that was a class rather than a struct), but it will work with List<T>.
A more flexible solution that doesn't depend on such a quirk of implementation would be:
public class SnapshotableListEnumerator<T> : IEnumerator<T>
{
private readonly IList<T> _list;
private int _idx;
private SnapshotableListEnumerator(IList<T> list, int idx)
{
_list = list;
_idx = idx;
}
public SnapshotableListEnumerator(IList<T> list)
: this(list, -1)
{
}
public bool MoveNext()
{
// Note that this enumerator doesn't complain about the list
// changing during enumeration, but we do want to check that
// a change doesn't push us past the end of the list, rather
// than caching the size.
if(_idx >= _list.Count)
return false;
++_idx;
return true;
}
public void Reset()
{
_idx = -1;
}
public T Current
{
get
{
if(_idx < 0 || _idx >= _list.Count)
throw new InvalidOperationException();
return _list[_idx];
}
}
object IEnumerator.Current
{
get { return Current; }
}
public void Dispose()
{
}
public SnapshotableListEnumerator<T> Snapshot()
{
return new SnapshotableListEnumerator<T>(_list, _idx);
}
}
public static class SnapshotableListEnumeratorHelper
{
public static SnapshotableListEnumerator<T> GetSnapshotableEnumerator<T>(this IList<T> list)
{
return new SnapshotableListEnumerator<T>(list);
}
}
Now you can call GetSnapshotableEnumerator() on any implementation of IList<T> and use its Snapshot() method whenever you want a copy of the position within the enumeration.
Do you definitely need an IEnumerator instance? Why not enumerate using the index and store that in your own variable?
var list = new List<string>(new { "a", "b", "c" });
var pos = 2; // this is the position
richTextBoxOutput.AppendText(list[pos]);
You can reset at any time with:
pos = (desired position);
During the development of one of my projects, I encountered an issue regarding generic types.
The project requires me to write a class that would act as a source of list objects. Suppose I had the following class:
public class TablesProvider
{
private readonly List[] _tables;
public TablesProvider()
{
// initialize the tables var here....
}
public List<TItem> GetTable<TItem>()
{
return (List<TItem>)_tables.Single(x => x is List<TItem>);
}
}
This class obviously doesn't work, because the List type is a generic type and therefore the generic arguments should be specified.
So I made an abstract type called MyList, that would be derived by a more specific type MyList<TItem> in order to escape this requirement, and edited the TablesProvider a little.
public class TablesProvider
{
private readonly MyList[] _tables;
public TablesProvider()
{
// initialize the tables var here....
}
public MyList<TItem> GetTable<TItem>()
{
return (MyList<TItem>)_tables.Single(x => x is MyList<TItem>);
}
}
public abstract class MyList
{
// ...
}
public class MyList<TItem> : MyList, IList<TItem>
{
private readonly List<TItem> _elements = new List<TItem>();
public TItem this[int index]
{
get { return _elements[index]; }
set { _elements[index] = value; }
}
// ...
}
This works quite well. There is only one problem left. Suppose I had 45 different collections, each defined with a different generic argument. What would be the best way of initializing all of those collections? I cannot use a for loop here, since generic parameters are specified at compile-time and not at runtime, and therefore a construction like this wouldn't be possible:
for (int i = 0; i < 45; i++)
_tables[i] = new MyList<GenericParameters[i]>();
My ultimate goal is to have the luxury to just do something like this...
var table = _tablesProvider.GetTable<SomeClass>();
var element = table[3];
var propertyValue = element.SomeProperty;
... without the need to cast the variable element in order to access its type-specific members.
It is probably worth mentioning that the amount of different list objects is fixed to 45. This will not change. In theory, I could initialize the array line by line, or have 45 properties or variables instead. Both of these options, however, sound as a rather cheap solution to me, but I will accept one of them if there is no other way.
Any of you got some ideas? Am I doing this completely wrong? Should I consider an other structure?
Thanks in advance.
Yes, it is possible to do what you are describing if you use reflection.
Supposing that your hypothetical GenericParameters array is an array of Types (since you can't have an array of type identifiers), you can define this helper function:
private MyList MakeList(Type t)
{
return (MyList)Activator.CreateInstance(typeof(MyList<>).MakeGenericType(t));
}
And that will allow you to do this:
public TablesProvider()
{
var GenericParameters = new[] { typeof(string), typeof(int), typeof(DateTime) };
_tables = new MyList[GenericParameters.Length];
for (int i = 0; i < GenericParameters.Length; i++)
{
_tables[i] = MakeList(GenericParameters[i]);
}
}
You can even use LINQ if you want:
public TablesProvider()
{
var GenericParameters = new[] { typeof(string), typeof(int), typeof(DateTime) };
_tables = GenericParameters.Select(MakeList).ToArray();
}
Previous answer:
Well, the reality is that you're going to have a list of 45 different types somewhere, which pretty much means you're going to have 45 different lines of similar code. So one could say the goal is to make those lines as concise as possible.
One way to do so would be to add a helper function:
private void AddTable<T>()
{
_tables.Add(new MyTable<T>());
}
(this assumes changing _tables to a List<MyTable>)
Then you could just do:
AddTable<Type1>();
AddTable<Type2>();
AddTable<Type3>();
AddTable<Type4>();
this implementation works
public class TablesProvider
{
private readonly List<object> _tables;
public TablesProvider()
{
_tables = new List<object>();
}
public IList<TItem> GetTable<TItem>()
{
var lst = (List<TItem>)_tables.SingleOrDefault(x => x is List<TItem>);
if (lst == null)
{
lst = new List<TItem>();
_tables.Add(lst);
}
return lst;
}
}
it creates List of TItem when necessary; next time it returns the same list for TItem. it is lazy initialization
so you can do invoke
var table = _tablesProvider.GetTable<SomeClass>();
without any code like this:
for (int i = 0; i < 45; i++)
_tables[i] = new MyList<GenericParameters[i]>();
it is not ThreadSafe
Is there a significant complexity difference between these two implementation or does the compiler optimize it anyway?
Usage:
for(int i = 0; i < int.MaxValue; i++)
{
foreach(var item in GoodItems)
{
if(DoSomethingBad(item))
break; // this is later added.
}
}
Implementation (1):
public IEnumerable<T> GoodItems
{
get { return _list.Where(x => x.IsGood); }
}
Implementation (2):
public IEnumerable<T> GoodItems
{
get { foreach(var item in _list.Where(x => x.IsGood)) yield return item; }
}
It appears that IEnumerable methods should always be implemented using (2)? When is one better than the other?
I just built an example program and then used ILSpy to examine the output assembly. The second option will actually generate an extra class that wraps the call to Where but adds zero value to the code. The extra layer the code must follow will probably not cause performance issues in most programs but consider all the extra syntax just to perform the same thing at a slightly slower speed. Not worth it in my book.
where uses yield return internally. You don't need to wrap it in another yield return.
You do _list.where(x => x.IsGood); in both. With that said, isn't it obvious which has to be the better usage?
yield return has its usages, but this scenario, especially in a getter, is not the one
The extra code without payload in "implementation 2" is the less evil here.
Both variants lead to undesirable creation of new object each time you call the property getter. So, results of two sequential getter calls will not be equal:
interface IItem
{
bool IsGood { get; set; }
}
class ItemsContainer<T>
where T : IItem
{
private readonly List<T> items = new List<T>();
public IEnumerable<T> GoodItems
{
get { return items.Where(item => item.IsGood); }
}
// ...
}
// somewhere in code
class Item : IItem { /* ... */ }
var container = new ItemsContainer<Item>();
Console.WriteLine(container.GoodItems == container.GoodItems); // False; Oops!
You should avoid this side-effect:
class ItemsContainer<T>
where T : IItem
{
private readonly List<T> items;
private readonly Lazy<IEnumerable<T>> goodItems;
public ItemsContainer()
{
this.items = new List<T>();
this.goodItems = new Lazy<IEnumerable<T>>(() => items.Where(item => item.IsGood));
}
public IEnumerable<T> GoodItems
{
get { return goodItems.Value; }
}
// ...
}
or make a method instead of property:
public IEnumerable<T> GetGoodItems()
{
return _list.Where(x => x.IsGood);
}
Also, the property is not a good idea, if you want to provide snapshot of your items to the client code.
Internally, the first version gets compiled down to something that looks like this:
public IEnumerable<T> GoodItems
{
get
{
foreach (var item in _list)
if (item.IsGood)
yield return item;
}
}
Whereas the second one will now look something like:
public IEnumerable<T> GoodItems
{
get
{
foreach (var item in GoodItemsHelper)
yield return item;
}
}
private IEnumerable<T> GoodItemsHelper
{
get
{
foreach (var item in _list)
if (item.IsGood)
yield return item;
}
}
The Where clause in LINQ is implemented with deferred execution. So there's no need to apply the foreach (...) yield return ... pattern. You're making more work for yourself, and potentially for the runtime.
I don't know if the second version gets jitted to the same thing as the first. Semantically, the two are distinct in that the first does a single round of deferred execution while the second does two rounds. On those grounds I'd argue that the second would be more complex.
The real question you need to ask is: When you're exposing the IEnumerable, what guarantees are you making? Are you saying that you want to simply provide forward iteration? Or are you stating that your interface provides deferred execution?
In the code below, my intent for is to simply provide forward enumeration without random access:
private List<Int32> _Foo = new List<Int32>() { 1, 2, 3, 4, 5 };
public IEnumerable<Int32> Foo
{
get
{
return _Foo;
}
}
But here, I want to prevent unnecessary computation. I want my expensive computation to be performed only when a result is requested.
private List<Int32> _Foo = new List<Int32>() { 1, 2, 3, 4, 5 };
public IEnumerable<Int32> Foo
{
get
{
foreach (var item in _Foo)
{
var result = DoSomethingExpensive(item);
yield return result;
}
}
}
Even though both versions of Foo look identical on the outside, their internal implementation does different things. That's the part that you need to watch out for. When you use LINQ, you don't need to worry about deferring execution since most operators do it for you. In your own code, you may wish to go with the first or second depending on your needs.