Проблемы с методом расширения ForEach через IEnumerable - PullRequest
1 голос
/ 11 марта 2011

Выполняя базовую проверку коллекции 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 попадает в 'item' в 'source'.

Вот код вызова (переменные 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));

И, наконец, цель действия - сохранение загружаемого файла - мы никогда не появлялисьдаже добраться сюда, но на всякий случай вот оно:

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 ]

1 голос
/ 11 марта 2011

Почему бы вам просто не позвонить ToList().ForEach() на оригинале IEnumerable<T>.

0 голосов
/ 11 марта 2011

Сначала напишите общий метод расширения:

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.PostedFile is HttpPostedFile:

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));
0 голосов
/ 11 марта 2011

Я думаю, это то, что вы хотите

Ваш класс, который расширяется 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
  });
...