Как создать динамическую функцию выбора проекции LINQ из строки [] имен?

Использование С#...

Есть ли способ указать имена свойств для проекционной функции в методе выбора LINQ из массива.

public class Album
{
    public int Id { get; set; }
    public string Name { get; set; }
    public short Rate { get; set; }
    public string Genre { get; set; }
    public short Tracks { get; set; }
}

public class Class1
{
    private void Some<T>()
    {
        // Example of source
        var names = new[] { "Id", "Name", "Tracks" };

        var query = myDataContext.
                    GetTable<T>.
                    AsQueryable().
                    Select( /* dynamic projection from names array */ );

                    // something like
                    // Select(x => new
                    //     {
                    //         x.Id,
                    //         x.Name,
                    //         x.Tracks
                    //     }

        GoAndDoSomethingWith(query);
    }
}

Можно ли это сделать без System.Linq.Dynamic?

Ответ 1

Вы можете использовать отражения и динамические типы для создания объекта только с указанными полями/свойствами.

Ниже приведен простой способ сделать это. Вы можете выполнять оптимизацию, например, иметь кеш типа для отражения. Но это должно работать для простых полей/свойств.

public static object DynamicProjection(object input, IEnumerable<string> properties)
{
    var type = input.GetType();
    dynamic dObject = new ExpandoObject();
    var dDict = dObject as IDictionary<string, object>;

    foreach (var p in properties)
    {
        var field = type.GetField(p);
        if (field != null)
            dDict [p] = field.GetValue(input);

        var prop = type.GetProperty(p);
        if (prop != null && prop.GetIndexParameters().Length == 0)
            dDict[p] = prop.GetValue(input, null);
    }

    return dObject;
}

Использование:

//...
var names = new[] { "Id", "Name", "Tracks" };
var projection = collection.Select(x => DynamicProjection(x, names));
//...