在IEnumerable <request.files> </request.files>上的ForEach扩展方法的问题

时间:2011-03-11 06:02:25

标签: c# linq foreach extension-methods ienumerable

在对ASP.Net(4.0)Request.Files(上传)集合进行一些基本验证时,我决定尝试使用LINQ。

该集合为IEnumerable<T>,因此不提供ForEach。愚蠢地,我决定构建一个可以完成这项工作的扩展方法。对不起,说没那么成功......

运行扩展方法(如下所示)会引发下一个错误:

  

无法将“System.String”类型的对象强制转换为“System.Web.HttpPostedFile”

显然我没有得到什么,但我看不出它是什么,所以冒着看起来像个白痴的风险(不会是第一次)这里是3个块的代码,还有一个承诺感谢任何帮助。

首先,使用Action参数的扩展方法:

//Extend ForEach to IEnumerated Files
public static IEnumerable<HttpPostedFileWrapper> ForEach<T>(this IEnumerable<HttpPostedFileWrapper> source, Action<HttpPostedFileWrapper> action)
{
   //breaks on first 'item' init
   foreach (HttpPostedFileWrapper item in source)
        action(item);
    return source;
}

当内部foreach循环命中'source'中的'item'时,会发生错误。

这是调用代码(变量MaxFileTries和attachPath之前已正确设置):

var files = Request.Files.Cast<HttpPostedFile>()
    .Select(file => new HttpPostedFileWrapper(file))
    .Where(file => file.ContentLength > 0
        && file.ContentLength <= MaxFileSize
        && file.FileName.Length > 0)
    .ForEach<HttpPostedFileWrapper>(f => f.SaveUpload(attachPath, MaxFileTries));

最后,Action目标,保存上传文件 - 我们似乎甚至没有到达这里,但为了以防万一,这里是:

public static HttpPostedFileWrapper SaveUpload(this HttpPostedFileWrapper f, string attachPath, int MaxFileTries)
{
    // we can only upload the same file MaxTries times in one session
    int tries = 0;
    string saveName = f.FileName.Substring(f.FileName.LastIndexOf("\\") + 1);   //strip any local
    string path = attachPath + saveName;
    while (File.Exists(path) && tries <= MaxFileTries)
    {
        tries++;
        path = attachPath + " (" + tries.ToString() + ")" + saveName;
    }
    if (tries <= MaxFileTries)
    {
        if (!Directory.Exists(attachPath)) Directory.CreateDirectory(attachPath);
        f.SaveAs(path);
    }
    return f;
}

我承认上面的一些内容是“找到的”一起拼凑起来,所以我很可能得到我应得的东西,但如果有人对此有很好的了解(或者至少已经通过),也许我可以学点东西。

感谢任何人。

3 个答案:

答案 0 :(得分:1)

为什么不在原始ToList().ForEach()上拨打IEnumerable<T>

答案 1 :(得分:0)

我认为这就是你想要的

扩展HttpFileCollection的课程应为

  public static class HttpPostedFileExtension
  {
    //Extend ForEach to IEnumerated Files
    public static void ProcessPostedFiles(this HttpFileCollection source, Func<HttpPostedFile, bool> predicate, Action<HttpPostedFile> action)
    {
      foreach (var item in source.AllKeys)
      {
        var httpPostedFile = source[item];
        if (predicate(httpPostedFile))
          action(httpPostedFile);
      }
    }  
  }

然后你可以这样使用它:

  Request.Files.ProcessPostedFiles(
  postedFile =>
  {
    return (postedFile.ContentLength > 0 && postedFile.FileName.Length > 0);      
  },
  pFile =>
  {
    //Do something with pFile which is an Instance of HttpPosteFile
  });

答案 2 :(得分:0)

首先,编写一个通用的扩展方法:

public static IEnumerable<T> ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
   foreach (T item in source)
        action(item);
    return source; // or void, without return
}

然后,Request.Files可投放到IEnumerable<string>,而不是IEnumerable<HttpPostedFile>

IEnumerable<string> requestFiles = this.Request.Files.Cast<string>();

但确实System.Web.UI.WebControls.FileUpload.PostedFileHttpPostedFile

HttpPostedFile file = fileUpload.PostedFile;
HttpPostedFileWrapper wrapper = new HttpPostedFileWrapper(file);

但它是单身,而不是集合。从哪里获得你的收藏?


另一种扩展方法:

public static IEnumerable<HttpPostedFile> ToEnumerable(this HttpFileCollection collection)
{
    foreach (var item in collection.AllKeys)
    {
        yield return collection[item];
    }
}

用法:

IEnumerable<HttpPostedFile> files = this.Request.Files.ToEnumerable();
IEnumerable<HttpPostedFileWrapper> wrappers = files.Select(f => new HttpPostedFileWrapper(f));