Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass a method extension as an argument

How can I pass an extension method as an argument to the constructor of a class, and have methods in that class use that extension as an extension?

For example: this is a file which contains an IEnumerable extension method:

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;
        }
    }
 }

}

I want to be able to pass IsImageFile() as an argument to a constructor to this object, so that methods in that class can use the IsImageFile as a method extension:

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());
like image 201
Cardinal Fang Avatar asked Dec 08 '25 10:12

Cardinal Fang


1 Answers

How can I pass an extension method as an argument to the constructor of a class... ?

Make the argument a delegate that matches the signature you're looking for. For example, Func<IEnumerable<FileInfo>, IEnumerable<FileInfo>> would work in the case you gave.

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

Note that in this case you will either have to identify the method using its static location, or using a lambda expression:

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

... , and have methods in that class use that extension as an extension?

This cannot be done. Extension methods are just special syntax sugar, and have a lot of rules around how they can be used. This information does not transfer when you create a delegate from the extension method. So you have to call the delegate as a regular method.

        iEnumerableFileInfo = new[] { _directories[i] }
            .Traverse(dir => getDirectoryInfosWithoutThrowing(dir))
            .SelectMany(dir => _myFilterMethod(getFileInfosWithoutThrowing(dir)));
like image 166
StriplingWarrior Avatar answered Dec 10 '25 00:12

StriplingWarrior