How to make this linq efficient - c#

I have this code snippet where we get a collection from COM Dll
public BOCollection SelectedObjects{
get
{
IMSICDPInterfacesLib.IJMonikerElements oIJMonikerElements;
oIJMonikerElements = m_oIJSelectSet.Elements as IMSICDPInterfacesLib.IJMonikerElements;
BOCollection oBusinessObjects = new BOCollection(oIJMonikerElements);
return oBusinessObjects;
}
}
Now BOCollection does implement IEnumerable. So would it be better to change it to
public IEnumerable<BusinessObject> SelectedObjects
So as to get the iterator goodness ? Or is there another way ?
thanks
Sunit

Are you wanting to return IEnumerable so you get deferred execution? First off, you wouldn't want to do this in a property, as I'm sure FxCop will yell at you for that. Here's how I suggest you change things so you can benefit from both deferred execution and LINQ.
Change the m_oIJSelectSet.Elements property to a method that returns IEnumerable like so:
public IEnumerable<IJMonikeElements> GetElements() {
// Do some magic here to determine which elements are selected
return (from e in this.allElements where e.IsSelected select e).AsEnumerable();
// This could also be a complicated loop
// while (someCondition()) {
// bool isSelected = false;
// var item = this.allItems[i++];
// Complicated logic determine if item is selected
// if (isSelected) {
// yield return item;
// }
}
}
public IEnumerable<BusinessObject> GetSelectedObjects() {
return m_oIJSelectSet.GetElements().Cast<BusinessObject>();
}
Now, you'll have complete deferred execution and LINQ support.

If BOCollection implements IEnumerable, then you've already got the iterator goodness. Just throw it in a for or foreach loop.

The problem with IEnumerable<T> is yes, it will give you "Linq goodness", but the lowest common denominator of Linq goodness. Better to return IList<T> or even IQueryable<T> (if you can do this).
For example if somebody wanted to get the 4th element, IEnumerable<T> doesn't makes sense if you are already storing the objects in an array or list.
To get IQueryable<T> from a List<T> do this:
IQueryable<int> query = list.AsQueryable();

Related

Any benefit to loop with nested condition in the ReSharper way?

When using a foreach loop with a nested condition inside, I ever write in the following way:
foreach (RadioButton item in listOfRadioButtons)
{
if (item.IsChecked == true)
{
// sometging
}
}
But I've installed ReSharper and it suggests to change this loop to the following form (removing the if and using a lambda):
foreach (RadioButton item in listOfRadioButtons.Where(item => item.IsChecked == true))
{
// something
}
In my experience, the ReSharper way will loop two times: one to generate the filtered IEnumerable, and after to loop the results of the .Where query again.
I am correct? If so, why is ReSharper suggesting this? Because in my opinion, the first is also more reliable.
Note: The default IsChecked property of the WPF RadioButton is a Nullable bool, so it's need a == true, a .Value, or a cast to bool inside a condition to return bool.
In my experience, the ReSharper way will loop two times: one to
generate the filtered IEnumerable, and after to loop the results of
the .Where query again.
Nope, it will loop only once. Where does not loop your collection - it only creates iterator which will be used to enumerate your collection. Here is how LINQ solution looks like:
using(var iterator = listOfRadioButtons.Where(rb => rb.IsChecked == true))
{
while(iterator.MoveNext())
{
RadioButton item = iterator.Current;
// something
}
}
Your original code is better for performance - you will avoid creating delegate and passing it to instance of WhereEnumerableIterator, and then executing delegate for each item in source sequence. But you should note, as #dcastro pointed, difference will be really small and does not worth noting until you will have to optimize this particular loop.
Solution suggested by ReSharper is (maybe) better for readability. I personally like simple if condition in a loop.
UPDATE: Where iterator can be simplified to (also some interfaces are omitted)
public class WhereEnumerableIterator<T> : IEnumerable<T>, IDisposable
{
private IEnumerator<T> _enumerator;
private Func<T,bool> _predicate;
public WhereEnumerableIterator(IEnumerable<T> source, Func<T,bool> predicate)
{
_predicate = predicate;
_enumerator = source.GetEnumerator();
}
public bool MoveNext()
{
while (_enumerator.MoveNext())
{
if (_predicate(_enumerator.Current))
{
Current = _enumerator.Current;
return true;
}
}
return false;
}
public T Current { get; private set; }
public void Dispose()
{
if (_enumerator != null)
_enumerator.Dispose();
}
}
Main idea here - it enumerates original source only when you ask it to move to next item. Then iterator goes to next item in original source and checks if it matches predicate. If match found, then it returns current item and puts enumerating source on hold.
So, until you will not ask items from this iterator, it will not enumerate source. If you will call ToList() on this iterator, it will enumerate source sequence and return all matched items, which will be saved to new list.

decorate IEnumerable without looping

I need to create an IEnummerable of DcumentSearch object from IQueryable
The following code causes the database to load the entire result which makes my app slow.
public static IEnumerable<DocumentSearch> BuildDocumentSearch(IQueryable<Document> documents)
{
var enumerator = documents.GetEnumerator();
while(enumerator.MoveNext())
{
yield return new DocumentSearch(enumerator.Current);
}
}
The natural way of writing this is:
public static IEnumerable<DocumentSearch> BuildDocumentSearch(IQueryable<Document> documents)
{
return documents.Select(doc => new DocumentSearch(doc));
}
When you call one of the IEnumerable extension methods like Select, Where, OrderBy etc, you are still adding to the recipe for the results that will be returned. When you try to access an element of an IEnumerable (as in your example), the result set must be resolved at that time.
For what it's worth, your while loop would be more naturally written as a foreach loop, though it should have the same semantics about when the query is executed.

AsEnumerable and how it affects a yield and a SqlDataReader

I'm trying to understand what the affect of AsEnumerable() has over my data when iterating over it. I have a mock in-memory list. If I foreach over it with first calling ToList(), this forces evaluation and my printout looks like this (see code at the bottom of this post to explain output):
entering da
yield return
yield return
yield return
exiting da
doing something to aaron
doing something to jeremy
doing something to brendan
All makes sense. The ToList() forces the yields in the repository to execute first into a list, then we get our foreach iteration. All good so far.
When I do the same except use AsEnumerable(), based on what I've read regarding IQueryable (I understand this isn't IQueryable), I would have thought this also forces evaluation, but it does not. It looks like this:
entering da
yield return
doing something to aaron
yield return
doing something to jeremy
yield return
doing something to brendan
exiting da
As it would if I never even called AsEnumerable(), so my question is:
Why does AsEnumerable behave differently for an in memory collection vs linq to sql and its IQueryable return type?
How would all this change when my repository is changed to using a SqlDataReader and doing a yield return inside of the reader (whilst calling Read() method). Would the rows coming from SqlServer that are buffered in the clients network buffer be fully evaluated before executing the foreach (normally a yield here will cause a "pause" in the repo while each row is processed by the foreach block. I know if I call ToList() first in this case, I can force evaluation of the SqlDataReader, so does AsEnumerable do the same here?
Note: I am not interested in whether putting yield into a SqlDataReader is a good idea, given it might hold the connection open, I've beaten this topic to death already :)
Here is my test code:
public class TestClient
{
public void Execute()
{
var data = MockRepo.GetData();
foreach (var p in data.AsEnumerable()) //or .ToList()
{
Console.WriteLine("doing something to {0}", p.Name);
}
Console.ReadKey();
}
}
public class Person
{
public Person(string name)
{
Name = name;
}
public string Name { get; set; }
}
public class MockRepo
{
private static readonly List<Person> items = new List<Person>(3)
{
new Person("aaron"),
new Person("jeremy"),
new Person("brendan")
};
public static IEnumerable<Person> GetData()
{
Console.WriteLine("entering da");
var enumerator = items.GetEnumerator();
while (enumerator.MoveNext())
{
Console.WriteLine("yield return");
yield return enumerator.Current;
}
Console.WriteLine("exiting da");
}
}
AsEnumerable does nothing except change the expression type to IEnumerable<T>. When it's used in a query like this:
var query = db.Customers
.Where(x => x.Foo)
.AsEnumerable()
.Where(x => x.Bar);
... that just means you'll use Queryable.Where for the first predicate (so that's converted to SQL), and Enumerable.Where for the second predicate (so that's executed in your .NET code).
It doesn't force evaluation. It doesn't do anything. It doesn't even check whether it's called on null.
See my Edulinq blog post on AsEnumerable for more information.
#Jon Skeet has already posted what AsEnumerable() does - it just changes the compile time type. But why would you use it?
Essentially by changing the expression from an IQueryable to an IEnumerable you can now use Linq to Objects (instead of the IQueryable implementation by your database provider) without any restriction - there does not have to be an equivalent method on the database side, so you can freely perform object transformation, remote calls (if required) or any sort of string manipulation.
That said you will want to do all the filtering you can while you are still working on the database (IQueryable) - otherwise you would be bringing all these rows into memory which will cost you - and only then use AsEnumerable() to do your final transformations afterwards.
According to the MSDN documentation:
The AsEnumerable(Of TSource)(IEnumerable(Of TSource)) method has no
effect other than to change the compile-time type of source from a
type that implements IEnumerable(Of T) to IEnumerable(Of T) itself.
It should not cause any evaluation, just hint that you want to use IEnumerable methods vs. some other implementation (IQueryable, etc.).

"Possible multiple enumeration of IEnumerable" vs "Parameter can be declared with base type"

In Resharper 5, the following code led to the warning "Parameter can be declared with base type" for list:
public void DoSomething(List<string> list)
{
if (list.Any())
{
// ...
}
foreach (var item in list)
{
// ...
}
}
In Resharper 6, this is not the case. However, if I change the method to the following, I still get that warning:
public void DoSomething(List<string> list)
{
foreach (var item in list)
{
// ...
}
}
The reason is, that in this version, list is only enumerated once, so changing it to IEnumerable<string> will not automatically introduce another warning.
Now, if I change the first version manually to use an IEnumerable<string> instead of a List<string>, I will get that warning ("Possible multiple enumeration of IEnumerable") on both occurrences of list in the body of the method:
public void DoSomething(IEnumerable<string> list)
{
if (list.Any()) // <- here
{
// ...
}
foreach (var item in list) // <- and here
{
// ...
}
}
I understand, why, but I wonder, how to solve this warning, assuming, that the method really only needs an IEnumerable<T> and not a List<T>, because I just want to enumerate the items and I don't want to change the list.
Adding a list = list.ToList(); at the beginning of the method makes the warning go away:
public void DoSomething(IEnumerable<string> list)
{
list = list.ToList();
if (list.Any())
{
// ...
}
foreach (var item in list)
{
// ...
}
}
I understand, why that makes the warning go away, but it looks a bit like a hack to me...
Any suggestions, how to solve that warning better and still use the most general type possible in the method signature?
The following problems should all be solved for a good solution:
No call to ToList() inside the method, because it has a performance impact
No usage of ICollection<T> or even more specialized interfaces/classes, because they change the semantics of the method as seen from the caller.
No multiple iterations over an IEnumerable<T> and thus risking accessing a database multiple times or similar.
Note: I am aware that this is not a Resharper issue, and thus, I don't want to suppress this warning, but fix the underlying cause as the warning is legit.
UPDATE:
Please don't care about Any and the foreach. I don't need help in merging those statements to have only one enumeration of the enumerable.
It could really be anything in this method that enumerates the enumerable multiple times!
You should probably take an IEnumerable<T> and ignore the "multiple iterations" warning.
This message is warning you that if you pass a lazy enumerable (such as an iterator or a costly LINQ query) to your method, parts of the iterator will execute twice.
There is no perfect solution, choose one acording to the situation.
enumerable.ToList, you may optimize it by firstly trying "enumerable as List" as long as you don't modify the list
Iterate two times over the IEnumerable but make it clear for the caller (document it)
Split in two methods
Take List to avoid cost of "as"/ToList and potential cost of double enumeration
The first solution (ToList) is probably the most "correct" for a public method that could be working on any Enumerable.
You can ignore Resharper issues, the warning is legit in a general case but may be wrong in your specific situation. Especially if the method is intended for internal usage and you have full control on callers.
This class will give you a way to split the first item off of the enumeration and then have an IEnumerable for the rest of the enumeration without giving you a double enumeration, thus avoiding the potentially nasty performance hit. It's usage is like this (where T is whatever type you are enumerating):
var split = new SplitFirstEnumerable(currentIEnumerable);
T firstItem = split.First;
IEnumerable<T> remaining = split.Remaining;
Here is the class itself:
/// <summary>
/// Use this class when you want to pull the first item off of an IEnumerable
/// and then enumerate over the remaining elements and you want to avoid the
/// warning about "possible double iteration of IEnumerable" AND without constructing
/// a list or other duplicate data structure of the enumerable. You construct
/// this class from your existing IEnumerable and then use its First and
/// Remaining properties for your algorithm.
/// </summary>
/// <typeparam name="T">The type of item you are iterating over; there are no
/// "where" restrictions on this type.</typeparam>
public class SplitFirstEnumerable<T>
{
private readonly IEnumerator<T> _enumerator;
/// <summary>
/// Constructor
/// </summary>
/// <remarks>Will throw an exception if there are zero items in enumerable or
/// if the enumerable is already advanced past the last element.</remarks>
/// <param name="enumerable">The enumerable that you want to split</param>
public SplitFirstEnumerable(IEnumerable<T> enumerable)
{
_enumerator = enumerable.GetEnumerator();
if (_enumerator.MoveNext())
{
First = _enumerator.Current;
}
else
{
throw new ArgumentException("Parameter 'enumerable' must have at least 1 element to be split.");
}
}
/// <summary>
/// The first item of the original enumeration, equivalent to calling
/// enumerable.First().
/// </summary>
public T First { get; private set; }
/// <summary>
/// The items of the original enumeration minus the first, equivalent to calling
/// enumerable.Skip(1).
/// </summary>
public IEnumerable<T> Remaining
{
get
{
while (_enumerator.MoveNext())
{
yield return _enumerator.Current;
}
}
}
}
This does presuppose that the IEnumerable has at least one element to start. If you want to do more of a FirstOrDefault type setup, you'll need to catch the exception that would otherwise be thrown in the constructor.
There exists a general solution to address both Resharper warnings: the lack of guarantee for repeat-ability of IEnumerable, and the List base class (or potentially expensive ToList() workaround).
Create a specialized class, I.E "RepeatableEnumerable", implementing IEnumerable, with "GetEnumerator()" implemented with the following logic outline:
Yield all items already collected so far from the inner list.
If the wrapped enumerator has more items,
While the wrapped enumerator can move to the next item,
Get the current item from the inner enumerator.
Add the current item to the inner list.
Yield the current item
Mark the inner enumerator as having no more items.
Add extension methods and appropriate optimizations where the wrapped parameter is already repeatable. Resharper will no longer flag the indicated warnings on the following code:
public void DoSomething(IEnumerable<string> list)
{
var repeatable = list.ToRepeatableEnumeration();
if (repeatable.Any()) // <- no warning here anymore.
// Further, this will read at most one item from list. A
// query (SQL LINQ) with a 10,000 items, returning one item per second
// will pass this block in 1 second, unlike the ToList() solution / hack.
{
// ...
}
foreach (var item in repeatable) // <- and no warning here anymore, either.
// Further, this will read in lazy fashion. In the 10,000 item, one
// per second, query scenario, this loop will process the first item immediately
// (because it was read already for Any() above), and then proceed to
// process one item every second.
{
// ...
}
}
With a little work, you can also turn RepeatableEnumerable into LazyList, a full implementation of IList. That's beyond the scope of this particular problem though. :)
UPDATE: Code implementation requested in comments -- not sure why the original PDL wasn't enough, but in any case, the following faithfully implements the algorithm I suggested (My own implementation implements the full IList interface; that is a bit beyond the scope I want to release here... :) )
public class RepeatableEnumerable<T> : IEnumerable<T>
{
readonly List<T> innerList;
IEnumerator<T> innerEnumerator;
public RepeatableEnumerable( IEnumerator<T> innerEnumerator )
{
this.innerList = new List<T>();
this.innerEnumerator = innerEnumerator;
}
public IEnumerator<T> GetEnumerator()
{
// 1. Yield all items already collected so far from the inner list.
foreach( var item in innerList ) yield return item;
// 2. If the wrapped enumerator has more items
if( innerEnumerator != null )
{
// 2A. while the wrapped enumerator can move to the next item
while( innerEnumerator.MoveNext() )
{
// 1. Get the current item from the inner enumerator.
var item = innerEnumerator.Current;
// 2. Add the current item to the inner list.
innerList.Add( item );
// 3. Yield the current item
yield return item;
}
// 3. Mark the inner enumerator as having no more items.
innerEnumerator.Dispose();
innerEnumerator = null;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
// Add extension methods and appropriate optimizations where the wrapped parameter is already repeatable.
public static class RepeatableEnumerableExtensions
{
public static RepeatableEnumerable<T> ToRepeatableEnumerable<T>( this IEnumerable<T> items )
{
var result = ( items as RepeatableEnumerable<T> )
?? new RepeatableEnumerable<T>( items.GetEnumerator() );
return result;
}
}
I realize this question is old and already marked as answered, but I was surprised that nobody suggested manually iterating over the enumerator:
// NOTE: list is of type IEnumerable<T>.
// The name was taken from the OP's code.
var enumerator = list.GetEnumerator();
if (enumerator.MoveNext())
{
// Run your list.Any() logic here
...
do
{
var item = enumerator.Current;
// Run your foreach (var item in list) logic here
...
} while (enumerator.MoveNext());
}
Seems a lot more straightforward than the other answers here.
Generally speaking, what you need is some state object into which you can PUSH the items (within a foreach loop), and out of which you then get your final result.
The downside of the enumerable LINQ operators is that they actively enumerate the source instead of accepting items being pushed to them, so they don't meet your requirements.
If you e.g. just need the minimum and maximum values of a sequence of 1'000'000 integers which cost $1'000 worth of processor time to retrieve, you end up writing something like this:
public class MinMaxAggregator
{
private bool _any;
private int _min;
private int _max;
public void OnNext(int value)
{
if (!_any)
{
_min = _max = value;
_any = true;
}
else
{
if (value < _min) _min = value;
if (value > _max) _max = value;
}
}
public MinMax GetResult()
{
if (!_any) throw new InvalidOperationException("Sequence contains no elements.");
return new MinMax(_min, _max);
}
}
public static MinMax DoSomething(IEnumerable<int> source)
{
var aggr = new MinMaxAggregator();
foreach (var item in source) aggr.OnNext(item);
return aggr.GetResult();
}
In fact, you just re-implemented the logic of the Min() and Max() operators. Of course that's easy, but they are only examples for arbitrary complex logic you might otherwise easily express in a LINQish way.
The solution came to me on yesterday's night walk: we need to PUSH... that's REACTIVE! All the beloved operators also exist in a reactive version built for the push paradigm. They can be chained together at will to whatever complexity you need, just as their enumerable counterparts.
So the min/max example boils down to:
public static MinMax DoSomething(IEnumerable<int> source)
{
// bridge over to the observable world
var connectable = source.ToObservable(Scheduler.Immediate).Publish();
// express the desired result there (note: connectable is observed by multiple observers)
var combined = connectable.Min().CombineLatest(connectable.Max(), (min, max) => new MinMax(min, max));
// subscribe
var resultAsync = combined.GetAwaiter();
// unload the enumerable into connectable
connectable.Connect();
// pick up the result
return resultAsync.GetResult();
}
Why not:
bool any;
foreach (var item in list)
{
any = true;
// ...
}
if(any)
{
//...
}
Update: Personally, I wouldn't drastically change the code just to get around a warning like this. I would just disable the warning and continue on. The warning is suggesting you change the general flow of the code to make it better; if you're not making the code better (and arguably making it worse) to address the warning; then the point of the warning is missed.
For example:
// ReSharper disable PossibleMultipleEnumeration
public void DoSomething(IEnumerable<string> list)
{
if (list.Any()) // <- here
{
// ...
}
foreach (var item in list) // <- and here
{
// ...
}
}
// ReSharper restore PossibleMultipleEnumeration
UIMS* - Fundamentally, there is no great solve. IEnumerable<T> used to be the "very basic thing that represents a bunch of things of the same type, so using it in method sigs is Correct." It has now also become a "thing that might evaluate behind the scenes, and might take a while, so now you always have to worry about that."
It's as if IDictionary suddenly were extended to support lazy loading of values, via a LazyLoader property of type Func<TKey,TValue>. Actually that'd be neat to have, but not so neat to be added to IDictionary, because now every time we receive an IDictionary we have to worry about that. But that's where we are.
So it would seem that "if a method takes an IEnumerable and evals it twice, always force eval via ToList()" is the best you can do. And nice work by Jetbrains to give us this warning.
*(Unless I'm Missing Something . . . just made it up but it seems useful)
Be careful when accepting enumerables in your method. The "warning" for the base type is only a hint, the enumeration warning is a true warning.
However, your list will be enumerated at least two times because you do any and then a foreach. If you add a ToList() your enumeration will be enumerated three times - remove the ToList().
I would suggest to set resharpers warning settings for the base type to a hint. So you still have a hint (green underline) and the possibility to quickfix it (alt+enter) and no "warnings" in your file.
You should take care if enumerating the IEnumerable is an expensive action like loading something from file or database, or if you have a method which calculates values and uses yield return. In this case do a ToList() or ToArray() first to load/calculate all data only ONCE.
You could use ICollection<T> (or IList<T>). It's less specific than List<T>, but doesn't suffer from the multiple-enumeration problem.
Still I'd tend to use IEnumerable<T> in this case. You can also consider to refactor the code to enumerate only once.
Use an IList as your parameter type rather than IEnumerable - IEnumerable has different semantics to List whereas IList has the same
IEnumerable could be based on a non-seekable stream which is why you get the warnings
You can iterate only once :
public void DoSomething(IEnumerable<string> list)
{
bool isFirstItem = true;
foreach (var item in list)
{
if (isFirstItem)
{
isFirstItem = false;
// ...
}
// ...
}
}
There is something no one had said before (#Zebi). Any() already iterates trying to find the element. If you call a ToList(), it will iterate as well, to create a list. The initial idea of using IEnumerable is only to iterate, anything else provokes an iteration in order to perform. You should try to, inside a single loop, do everything.
And include in it your .Any() method.
if you pass a list of Action in your method you would have a cleaner iterated once code
public void DoSomething(IEnumerable<string> list, params Action<string>[] actions)
{
foreach (var item in list)
{
for(int i =0; i < actions.Count; i++)
{
actions[i](item);
}
}
}

IEnumerable to something that I can get a Count from?

I've got this:
private IEnumerable _myList;
I need to get a count off of that object. I was previously typing _myList to an array and getting the length, but now we are using this same bit of code with a different kind of object. It's still a Collection type (it's a strongly typed Subsonic Collection object), and everything works great, except for the bit that we need to get the total number of items in the object.
I've tried typing it to CollectionBase, and many many other types, but nothing works that will let me get a .Count or .Length or anything like that.
Can anyone point me in the right direction?
EDIT: I'm not using 3.5, I'm using 2. So, anything dealing with Linq won't work. Sorry for not posting this earlier.
Is this actually IEnumerable instead of IEnumerable<T>? If so, LINQ won't help you directly. (You can use Cast<T>() as suggested elsewhere, but that will be relatively slow - in particular, it won't be optimised for IList/IList<T> implementations.)
I suggest you write:
public static int Count(this IEnumerable sequence)
{
if (sequence == null)
{
throw new ArgumentNullException("sequence");
}
// Optimisation: won't optimise for collections which
// implement ICollection<T> but not ICollection, admittedly.
ICollection collection = sequence as ICollection;
if (collection != null)
{
return collection.Count;
}
IEnumerator iterator = sequence.GetEnumerator();
try
{
int count = 0;
while (iterator.MoveNext())
{
// Don't bother accessing Current - that might box
// a value, and we don't need it anyway
count++;
}
return count;
}
finally
{
IDisposable disposable = iterator as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
}
The System.Linq.Enumerable.Count extension method does this for a typed IEnumerable<T>.
For an untyped IEnumerable try making your own extension:
public static int Count(this IEnumerable source)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
ICollection collectionSource = source as ICollection;
if (collectionSource != null)
{
return collectionSource.Count;
}
int num = 0;
IEnumerator enumerator = source.GetEnumerator();
//try-finally block to ensure Enumerator gets disposed if disposable
try
{
while (enumerator.MoveNext())
{
num++;
}
}
finally
{
// check for disposal
IDisposable disposableEnumerator = enumerator as IDisposable;
if(disposableEnumerator != null)
{
disposableEnumerator.Dispose();
}
}
return num;
}
If you're using .NET 3.5, you can use Enumerable.Count() to get the count from any IEnumerable<T>.
This will not work off a non-generic IEnumerable, though - it requires IEnumerable<T>.
This should work, though, since Subsonic's collection classes implement the appropriate interfaces for you. You'll need to change your definition from IEnumerable to IEnumerable<MyClass>.
LINQ provides a Count() extension method.
using System.Linq;
...
var count = _myList.Count();
The type you use is IEnumerable, which doesn't have a Count property. But the generic equivalent, IEnumerable(T), has a Count property.
The obvious solution is to use IEnumerable(T), but if you can't, you could do something like this:
_myList.Cast<MyListItemType>().Count()
The cast is an easy way to convert a IEnumerable to an IEnumerable(SomeType) but obviously is not the best way to get the count performance-wise.
If performance is a factor, I'd just loop through the values to get the count, unless you know the underlying collection has a Count property (see Jon Skeet's answer...).
If you include the System.Linq namespace, IEnumerable<T> has a Count() extension method available. You can write your own extension method to get it on the non-generic version. Note this method will box value types, so if that might end up being a performance concern for you, go with Jon Skeet's solution. This is just simpler.
public static int Count(this IEnumerable enumerable)
{
int count = 0;
foreach(object item in enumerable)
{
count++;
}
return count;
}
What about calling .ToList()?
If the underlying object implements ICollection, then you can use the .Count() property.
I needed the same and I created IEnumerableList. The reason was that I didnt like to evaluate every time I need the count through whole enumerable object as it's done with the extension method Count().
More about it here: http://fknet.wordpress.com/2010/08/11/string-formatwith-extension/

Categories

Resources