C # Использование GetProperty для LINQ OrderBy с использованием FileInfo - PullRequest
1 голос
/ 07 марта 2019

Я пытаюсь использовать Отражение GetProperty, чтобы установить тип OrderBy Я хочу динамически .Значение orderByParam может быть таким, как "Length", "Name", "CreationTime" и т. Д. Это позволит мне добавить файлы в список в том порядке, который я хочу позже. ошибка , которую я получаю:

Объект не соответствует типу цели

.Что мне здесь не хватает?

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

Ответы [ 2 ]

1 голос
/ 07 марта 2019

Поместите его как

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

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

Поскольку вы хотите, чтобы значение свойства читалось из f (new FileInfo(f), если быть точным), а не orderByParam

0 голосов
/ 07 марта 2019

Проблема в том, что вы не используете параметр f в своем OrderBy

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

Вы делаете вещи намного сложнее, чем нужно.

Требование : учитывая имя каталога и имя одного из свойств класса FileInfo, дайте мне последовательность всех файлов в этом каталоге, упорядоченную по этому свойству.

Мой совет будетне использовать отражение для этого, но создать класс IComparer для вашего заказа.

Это имеет несколько преимуществ.Отражение довольно медленное.Компаратор также может быть использован для OrderByDescending.Но самое важное преимущество заключается в том, что вы можете контролировать, какие PropertyNames вы хотите заказать.

Вы можете отказаться от заказа по свойству Directory или по свойству Exists.Кроме того, чтобы добавить поддержку к заказу по "Длина", вы можете добавить поддержку к заказу по "ДЛИНА" / ​​"длина" / "ДЛИНА".Если вам нужна поддержка ввода из командной строки, вы можете добавить поддержку к порядку с помощью "-l" / "-L"

Если вы создаете класс сравнения, использование будет:

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 Comparer= FileInfoComparer.Create ("Length");DirectoryInfo directory = new DirectoryInfo (directoryPath);var orderFiles = directory.EnumerateFiles.Orderby (file => file, Comparer);

...