Сделать свойства класса параметрами для функции - PullRequest
2 голосов
/ 05 июня 2019

Мое намерение состоит в том, чтобы передать открытые свойства класса, например, сказать:

class MyTestClass
{
    public string Name { get; set; }
    public DateTime  StartedAt { get; set; }
    public TimeSpan Duration { get; set; }
}

функции и параметры:

static void MyCustomFunc(params Expression<Func<MyTestClass, object>>[] props)
{
    foreach (var p in props)
    {
        // The following only works for Name property, not for StartedAt or Duration
        MemberExpression member = p.Body as MemberExpression;
        PropertyInfo propertyInfo = (PropertyInfo)member.Member;

        string name = propertyInfo.Name;
        Type type = propertyInfo.PropertyType;
        Func<MyTestClass, object> func = p.Compile();
    }
}

Функция должна собирать эту информацию ипередать его в класс-экспортер, который экспортирует наборы MyTestClass объектов в файл CSV.

Выходные данные, записанные в файл CSV, зависят от количества, типа и порядка свойств, введенных в MyCustomFunc.

Так вот:

MyCustomFunc(x => x.Name, x => x.StartedAt);

создаетотличается от:

MyCustomFunc(x => x.StartedAt, x => x.Name);

и

MyCustomFunc(x => x.StartedAt, x => x.Name, x => x.Duration);

отличается от

MyCustomFunc(x => x.Duration, x => x.StartedAt, x => x.Name);

Моя проблема заключается в том, чтобы заставить отражение работать.По какой-то причине я не могу понять p.Body:

  • для {x => x.Name} равно {x.Name}, но
  • для {x => x.StartedAt} равно {Convert(x.StartedAt)}

Первый может быть обработан с помощью

MemberExpression member = p.Body as MemberExpression;

, а второй возвращает null, поэтому я получаю исключение нулевой ссылки.

1 Ответ

4 голосов
/ 05 июня 2019

Дело в жестком кодировании параметра типа заставило меня немного чесаться, поэтому я изменил это. У меня было ощущение, что ты собираешься возиться с этой частью дальше. Дайте мне знать, если это не так, и я вернусь.

public static void MyCustomFunc<T>(this T inst, params Expression<Func<T, object>>[] props)
{
    foreach (var p in props)
    {
        PropertyInfo propertyInfo = null;

        //  Because the return type of the lambda is object, when the property is a value 
        //  type, the Expression will have to be a unary expression to box the value. 
        //  The MemberExpression will be the operand from that UnaryExpression. 
        if (p.Body is UnaryExpression ue && ue.Operand is MemberExpression ueMember)
        {
            propertyInfo = (PropertyInfo)ueMember.Member;
        }
        else if (p.Body is MemberExpression member)
        {
            propertyInfo = (PropertyInfo)member.Member;
        }
        else
        {
            throw new ArgumentException("Parameters must be property access expressions " 
                + "in the form x => x.Property");
        }

        string name = propertyInfo.Name;
        Type type = propertyInfo.PropertyType;
        Func<T, object> func = p.Compile();
    }
}

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

new MyTestClass { Name = "Stan", StartedAt = DateTime.Now }
    .MyCustomFunc(x => x.Name, x => x.StartedAt);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...