1

I am trying to use the Reflection GetProperty to set the type of OrderBy I want dynamically. The orderByParam would have a value such as "Length", "Name", "CreationTime", etc. This will allow me to add the files to a list in the order I want later on. The error I am receiving is:

Object does not match target type

. What am I missing here?

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));
    }
}
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215

2 Answers2

1

Put it as

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

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

Since you want property value being read from f (new FileInfo(f), to be exact), not orderByParam

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
0

The problem is that you don't use parameter f in your OrderBy

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

You are making things way more complicated than needed.

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.

My advise would be not to use reflection for this, but to create an IComparer class for your ordering.

This has several advantages. Reflection is fairly slow. The comparer can also be used to OrderByDescending. But the most important advantage is that you can control which PropertyNames you want to order by.

You can refuse ordering by property Directory, or by property Exists. Besides to add support to order by "Length" you can add support to order by "LENGTH" / "length" / "lENgth". If you need to support command line input, you could add support to order by "-l" / "-L"

If you create a comparer class, usage would be:

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

The implementation of IComparer is fairly easy:

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

}

I created a private constructor, so only the Create function can create this comparer.

Usage:

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

Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116