2014-09-19 5 views
2

Как передать метод расширения в качестве аргумента конструктору класса, а методы в этом классе используют это расширение как расширение?Пропустить расширение метода в качестве аргумента

Например: это файл, который содержит IEnumerable метод расширения:

namespace System.Collections.Generic 
{ 
    public static partial class IEnumerableMethodExtensions 
    { 
     /// <summary> 
     /// Used by IsImageFile to determine if a file is a graphic type 
     /// we care about. (Not an Extension Method, just a helper method) 
     /// </summary> 
     public static string[] GraphicFileExtensions = new string[] { ".png", ".bmp", ".gif", ".jpg", ".jpeg" }; 

     /// <summary> 
     /// Method Extension - specifies that FileInfo IEnumerable should only 
     /// return files whose extension matches one in GraphicFileExtensions[]. 
     /// </summary> 
     /// <param name="files"></param> 
     /// <returns></returns> 
     public static IEnumerable<FileInfo> IsImageFile(this IEnumerable<FileInfo> files) 
     { 
      foreach (FileInfo file in files) 
      { 
      string ext = file.Extension.ToLower(); 
      if (GraphicFileExtensions.Contains(ext)) 
       yield return file; 
     } 
    } 
} 

}

Я хочу, чтобы иметь возможность пройти IsImageFile() в качестве аргумента конструктора для этого объекта, так что методы в этом классе могут использовать IsImageFile в качестве расширения метода:

public class MainFileInfoSource 
{ 
    public MainFileInfoSource(List<DirectoryInfo> Directories, 
       ENUMERABLE_METHOD_EXTENSION_FILE_FILTER TheMethodExtension) 
    { 
     _myFilterMethodExtension = TheMethodExtension; 
     _directories = Directories; 

     initializeFileInfoList(); 
    } 

    ... 

    /// <summary> 
    /// Initializes the Files list. 
    /// </summary> 
    private void initializeFileInfoList() 
    { 
    ... 
     for (int i = 0; i < _directories.Count; i++) 
     { 
      iEnumerableFileInfo = new[] { _directories[i] }.Traverse(dir => 
      getDirectoryInfosWithoutThrowing(dir)).SelectMany(dir => 
      getFileInfosWithoutThrowing(dir)._myFilterMethodExtension()); 
+1

http://stackoverflow.com/questions/1016033/extension-methods-defined-on-value-types-cannot-be-used-to-create-delegates-wh – AlexanderBrevig

+0

@AlexanderBrevig вы можете мне помочь понять, какая часть этого вопроса/ответа - мой прием? Видимо, я недостаточно умен, чтобы видеть связь. –

+0

Вы не можете этого сделать, потому что вызовы статических методов компилируются во время компиляции. Объяснение того, какова ваша фактическая цель, может помочь найти подходящий подход (например, метод расширения, реализованный с использованием шаблона локатора службы для поиска реализации). –

ответ

3

Как передать метод расширения в качестве аргумента в конструктор класса ...?

Сделать аргумент делегатом, который соответствует подписи, которую вы ищете. Например, Func<IEnumerable<FileInfo>, IEnumerable<FileInfo>> будет работать в том случае, если вы дали.

public MainFileInfoSource(List<DirectoryInfo> Directories, 
      Func<IEnumerable<FileInfo>, IEnumerable<FileInfo>> FilterMethod) 

Обратите внимание, что в этом случае вам придется либо определить метод с использованием его статического местоположения или с помощью лямбда-выражения:

var source = new MainFileInfoSource(directories, FileFilterExtensions.IsAwesome); 
var source2 = new MainFileInfoSource(directories, f => f.IsAwesome()); 

... и есть методы в этом классе использовать это расширение как расширение?

Этого не может быть сделано. Методы расширения - это просто особый синтаксический сахар, и у них есть много правил о том, как их можно использовать. Эта информация не передается при создании делегата из метода расширения. Поэтому вы должны вызвать делегата как обычный метод.

 iEnumerableFileInfo = new[] { _directories[i] } 
      .Traverse(dir => getDirectoryInfosWithoutThrowing(dir)) 
      .SelectMany(dir => _myFilterMethod(getFileInfosWithoutThrowing(dir))); 
+0

Спасибо. Это должно сработать. Я действительно хотел выразить это как расширение метода IEnumerable, и это ослепило меня каким-либо другим подходом. Слишком плохо, хотя, мне нравится наращивать методы наращивания.:-) –

+0

Я также могу написать «общий» метод расширения IEnumerable, который принимает строку фильтра в качестве аргумента и передает эту строку фильтра в мой конструктор. Если я действительно хочу заставить расширения метода. –

0

Не работает ли он для вас?

public class MainFileInfoSource 
{ 
    public MainFileInfoSource(List<DirectoryInfo> Directories, 
     Func<IEnumerable<FileInfo>, IEnumerable<FileInfo>> TheMethodExtension) 
    { 

    } 
} 

и

new MainFileInfoSource(null, IEnumerableMethodExtensions.IsImageFile); 

?

+0

Valentin, я буквально не мог понять, как получить расширение метода, которое появится после точки getFileInfosWithoutThrowing() (через Intellisense). Я думаю, что Александр и StriplingWarrior уточнили для меня, что C# не хочет, чтобы я попытался выразить делегата в качестве расширения метода. –

Смежные вопросы