C# 对使用 FileInfo 的 LINQ OrderBy 使用 GetProperty

C# Using GetProperty for LINQ OrderBy using FileInfo

我正在尝试使用 Reflection GetProperty 来设置 OrderBy 的类型 我想要 动态地 . orderByParam 会有一个值,例如 "Length""Name""CreationTime" 等。这将允许我稍后按照我想要的顺序将文件添加到列表中.我收到的 error 是:

Object does not match target type

。我在这里错过了什么?

try
{
    PropertyInfo propertyInfo = typeof(FileInfo).GetProperty(orderByParam);
    var files = Directory.GetFiles(strPath)
                         .OrderBy(f => propertyInfo.GetValue(orderByParam, null));  
                         //FileInfo(f).CreationTime))

    foreach (string str in files)
    {
        strFiles.Add(Path.GetFileName(str));
    }
}

把它写成

 PropertyInfo propertyInfo = typeof(FileInfo).GetProperty(orderByParam);

 var files = Directory
   .EnumerateFiles(strPath)
   .OrderBy(f => propertyInfo.GetValue(new FileInfo(f), null));  

因为您希望从 f(准确地说是 new FileInfo(f))读取 属性 值,而不是 orderByParam

问题是您没有在 OrderBy 中使用参数 f

.OrderBy(f => propertyInfo.GetValue(orderByParam, null)); 

你让事情变得比需要的更复杂。

Requirement: given the name of a Directory, and the name of one of the properties of class FileInfo, give me the sequence of all files in this directory ordered by this property.

我的建议是不要为此使用反射,而是为您的排序创建一个 IComparer class。

这有几个优点。反射相当慢。比较器也可用于 OrderByDescending。但最重要的优点是您可以控制要按哪些 PropertyNames 进行排序。

您可以通过属性Directory或属性Exists拒绝订购。除了添加对按 "Length" 排序的支持外,您还可以添加对按 "LENGTH" / "length" / "lENgth" 排序的支持。如果需要支持命令行输入,可以通过"-l" / "-L"

命令添加支持

如果您创建比较器 class,用法为:

string directoryName = ...
// TODO: exception if directoryName null or empty
DirectoryInfo directory = new DirectoryInfo(directoryName);
if (!directory.Exists) TODO: exception

IComparer<FileInfo> comparer = ...
IEnumerable<FileInfo> files = directory.EnumerateFiles();

IEnumerable<FileInfo> orderedFiles = files.OrderBy(file => file, comparer);

IComparer 的实现相当简单:

class FileInfoComparer<TKey> : IComparer<FileInfo>
{
    public static IComparer<FileInfo> Create(string propertyName)
    {
        // this Compare supports only property names of FileInfo
        // and maybe not even all property names

        switch (propertyName)
        {
            case "Name":
                  return new FileInfoComparer(fileInfo => fileInfo.Name);
            case "Length":
                  return new FileInfoComparer(fileInfo => fileInfo.Length);
            case "Extension"
                  return new FileInfoComparer(fileInfo => fileInfo.Extension);
            ...
            default:
                 throw new NotSupportedException("Ordering by this property not supported");
                 // for instance: property names "Directory" "Exists"
        }
    }

    private FileInfoComparer(Func<FileInfo, TKey> keySelector)
    {
        this.keySelector = keySelector;
    }

    private readonly Func<FileInfo, TKey> keySelector;
    private readonly IComparer<TKey> keyComparer = Comparer<TKey>.Default;

    public int Compare(FileInfo x, FileInfo y)
    {
        // TODO: decide what to do if x or y null. Exception? first or last in sort order?
        return keyComparer.Compare(this.keySelector(x), this.keySelector(y));
    }

}

我创建了一个私有构造函数,所以只有Create函数才能创建这个比较器。

用法:

var 比较器 = FileInfoComparer.Create("Length"); DirectoryInfo 目录 = new DirectoryInfo(directoryPath); var orderedFiles = directory.EnumerateFiles.Orderby(file => file, comparer);