views:

229

answers:

3

My code has something like this:

HttpFileCollection files

Instead of looping through each file and adding up the file.ContentLength to get the total length of all content e.g.

        int totalLength = 0;
        for (int i = 0; i < files.Count; i++)
        {
            totalLength += files[i].ContentLength;
        }

Is there a way I can do this with a lambda expression so I have something like..

int totalLength = files.[some sort of delegate here to do the addition].

Thanks in advance.

Edit: HttpFileCollection has a GetEnumeratorMethod but would it need to implement IEnumerable to use a lambda expression?

+5  A: 

You could use LINQ:

int totalLength = files.AllKeys.Select(k => files[k]).Sum(f => f.ContentLength);

Unfortunately, HttpFileCollection's enumerator returns an enumeration of strings. In order to get the actual objects (HttpPostedFile), you need to access the "dictionary" by key. This converts the enumerator to an enumeration of HttpPostedFile instances (via Select), then sums the content length.

Reed Copsey
Hi just to understand, why dont I need to iterate through the files and cast? Is there some sort of automatic enumeration taking place on the collection. Not quite got to grips with this despite reading "C# In Depth" :)
RemotecUk
HttpFileCollection implements IEnumerable, so you can enumerate it as "object"s. The above LINQ statement does the cast inline, and then handles the sum for you. It's, internally, basically the same as doing a foreach, casting to HttpPostedFile, then summing ContentLength (but much easier to read and write).
Reed Copsey
mmm - that shouldn't happen, given the code you posted above... Are you sure "files" is an HttpFileCollection, and not a collection of strings, somehow?
Reed Copsey
Sorry deleted my comment just before u replied as it wasnt relevant. The code is correct but somehow a string is getting into the file collection from the Request.Files object.(For reference my comment mentioned an invalid cast exception).
RemotecUk
I actually figured it out - my updated answer will work correctly.
Reed Copsey
What a wacky collection. :-)
Sam
You know, that "Select" is wholly unnecessary. files.AllKeys.Sum(x => files[x].ContentLength) works fine.
Protector one
+1  A: 

You need to cast it, like this:

int totalLength = files.Cast<HttpPostedFile>().Sum(f => f.ContentLength);
Sam
This doesn't work, actually - files.GetEnumerator returns an IEnumerable that is string values.
Reed Copsey
@Reed Copsey, you're right. `HttpFileCollection` is one totally screwed up collection.
Sam
+1  A: 

To add to the accepted answer, indeed, you can use this:

int totalLength = files.AllKeys.Select(k => files[k]).Sum(f => f.ContentLength);

The reason why you don't have to enumerate in your code is because the Sum extension method does that for you. If you run it through Reflector you eventually find this bit of code:

public static int Sum(this IEnumerable<int> source)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    int num = 0;
    foreach (int num2 in source)
    {
        num += num2;
    }
    return num;
}

As you see ,it's not really rocketscience. It's almost the same as your original code even!

Note: If you want to find this code, crack open System.Core, go to the System.Linq namespace and open the Enumerable class definition. You'll find these methods here (among other places I think).

Erik van Brakel
This doesn't work, actually - files.GetEnumerator returns an IEnumerable that is string values
Reed Copsey
Ah, I see you edited your answer. I'll update mine accordingly. Thanks :)
Erik van Brakel