Reputation: 1166
Hullo,
For some reason (that I can't work out) a function that returns an ilist keeps returning null when I call it (even though earlier in the same method it returns an empty ilist, but whatever) so I was making a function to take in several ilists and then output the total number of elements across all the lists (ignoring the null ones as to avoid an exception).
So far I have:
private int TotalItemsInLists(params IList[] lists)
{
int total = 0;
foreach (IList list in lists)
if (list != null)
total += list.Count;
return total;
}
but that causes problems in that params IList[] lists
doesn't seem to be called correctly, as the ILists are all lists of different types.
Anyone know how I can remedy this problem?
Thanks, Harry
Edit: Here is the code that calls it
private bool TooManyItems(Person person)
{
return TotalItemsInLists(jobService.BeingDevelopedBy(person), jobService.BeingTestedBy(person),
jobService.BeingFixedBy(person), quoteService.BeingProducedBy(person),
ticketService.BeingActivelyHandledBy(person),
ticketService.BeingTestedBy(person),
ticketService.AllAvailable(person)) > 10;
}
And here's an example of one of the methods they call (they're all pretty similar, just different databases and filters)
public IList<Ticket> BeingActivelyHandledBy(Person person)
{
return (from ticket in Query()
where ticket.Handler == person
&& ticket.Status == TicketStatus.Open
&& ticket.Release == null
select ticket).ToList();
}
Upvotes: 1
Views: 122
Reputation: 46108
If your IList<T>
s are all objects that implement ICollection
(which is likely, as most of the collection classes in the BCL that implement IList<T>
also implement ICollection
), then you can simply cast to ICollection
, although you will lose type-safety.
private int TotalItemsInLists(params object[] lists)
{
int total = 0;
// this casts each object implicitly to ICollection
foreach (ICollection list in lists)
if (list != null)
total += list.Count;
return total;
}
If not, then you need to go back to the non-generic IEnumerable
and use Cast<object>
:
private int TotalItemsInLists(params IEnumerable[] lists)
{
int total = 0;
foreach (IEnumerable list in lists)
if (list != null)
total += list.Cast<object>().Count();
return total;
}
Upvotes: 1
Reputation: 113412
Essentially, the reason your code doesn't work is because the generic IList<T>
does not implement the non-generic IList
interface (it's only coincidental that List<T>
happens to implement both interfaces.).
It appears that the static types of the arguments you are passing are all IList<SomeThing>
, so what you have clearly isn't going to work.
One workaround would be to just rely on the classic IEnumerable
interface and do all the leg-work in the method itself, i.e. figure out the fastest way to get each sub-sequence's count.
Here's an untested sample:
private static int TotalItemsInLists(params IEnumerable[] lists)
{
if(lists == null)
throw new ArgumentNullException("lists");
return lists.Sum(l => l == null ? 0 : GetCount(l));
}
private static int GetCount(IEnumerable source)
{
var collection = source as ICollection;
if (collection != null)
return collection.Count;
var genCollType = source.GetType().GetInterfaces()
.FirstOrDefault
(i => i.IsGenericType
&& i.GetGenericTypeDefinition() == typeof(ICollection<>));
if (genCollType != null)
return (int)genCollType.GetProperty("Count").GetValue(source, null);
return source.Cast<object>().Count();
}
Upvotes: 1
Reputation: 60694
If you have your list generation methods return for example List<Ticket>
instead of IList<Ticket>
it should work out just fine, since List<T>
implements IList
.
Upvotes: 1
Reputation: 8222
I think the only thing you can do is change the method to accept the non-generic IEnumerable
type.
private int TotalItemsInLists(params IEnumerable[] lists)
{
int total = 0;
foreach (var list in lists)
if (list != null)
total += list.Count();
return total;
}
If performance becomes a problem, you can do a quick check in the loop if the type is also a generic or non-generic ICollection and read its Count property directly.
Upvotes: 1
Reputation: 14880
You have to cast the input to IList
:
TotalItemsInLists((IList)jobService.BeingDevelopedBy(person), ...
Upvotes: 1