2

I have a view model in asp .net mvc 3 which has

IEnumerable<HttpPostedFileBase> files

In the view, I have a for loop that creates 9 input tags for these files.

I want to implement a check on the server-side to ensure atleast 3 files are being uploaded.

I tried putting a condition

if(files.Count() > 2) { // code here } 

However, that returns 9 as it also counts the null elements.

I can think of implementing a counter myself as below:

int count = 0;
@foreach(var file in files) {
  if(file != null && file.ContentLength > 0) { 
    count++; 
  }
}

Is this the best way to do this or is there a functionality already in asp .net mvc for this.

Khan
  • 17,904
  • 5
  • 47
  • 59
Tripping
  • 919
  • 4
  • 18
  • 36

3 Answers3

6
files.Count(file=>file != null && file.ContentLength > 0);
L.B
  • 114,136
  • 19
  • 178
  • 224
  • @Tripping No, I won't be worse that your loop(I don't mean it is bad.) – L.B Nov 16 '12 at 17:28
  • Should I use a list and length instead? I am very new to asp .net or web development in general and was reading that using count is not a good idea. Many Thanks – Tripping Nov 16 '12 at 17:30
  • @Tripping Before thinking micro optimizations, try to write a readable/maintainable code. When you check null and ContentLength you will have to loop through the list and Linq won't be slower. – L.B Nov 16 '12 at 17:31
  • @Tripping Do you have a few hundred thousand (or million) items in your list, or are you performing this operation a few hundred thousand times? If so, there may be a preferable way (you could use `Skip` and `Any()` to short circuit the operation and end early) but odds are your code is more than fast enough even with a naive algorithm. – Servy Nov 16 '12 at 17:31
  • Why don't you change your model to `List` and call `.Count` property on it – Ilia G Nov 16 '12 at 17:32
  • @IliaG Because he's not counting every item, he's counting just the items that meet certain criteria. – Servy Nov 16 '12 at 17:32
  • @Servy I get that, but he can filter them once in the controller and work with filtered list inside the view. – Ilia G Nov 16 '12 at 17:40
4

Use a predicate to filter the count:

files.Where(file => file != null).Count()

Or simpler, just files.Count(file => file != null).

McGarnagle
  • 101,349
  • 31
  • 229
  • 260
1

Any time you see the paradigm of enumerable.Count() > X you could use the following method which gives you the benefit of ending as soon as you know you have enough items:

public static bool HasAtLeast<T>(IEnumerable<T> source, int number)
{
    return source.Skip(number - 1).Any();
}

Given that method you could write:

if(files.Where(file => file != null && file.ContentLength > 0)
    .HasAtLeast(2))
{
    //code goes here
}

Now, is this a major improvement, no, probably not. You'd need to either be executing this code many, many thousands of times, have a gigantic enumeration, or have an enumeration that is expensive to enumerate (if it's the result of a LINQ query performing long running methods for example) for it to matter. If you didn't put HasAtLeast into it's own method it would also decrease readability, so that alone wouldn't be worth the (usually small) performance advantage.

Servy
  • 202,030
  • 26
  • 332
  • 449