Получение имен / значений нескольких свойств - PullRequest
0 голосов
/ 24 февраля 2020

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

public TModel Get (Expression<Func<object>> param)
{
        using (OracleConnection connection = new OracleConnection(GetConnectionString()))
        {
            connection.Open();

            var propertyName= ((MemberExpression)param.Body).Member.Name;

            var value = param.Compile()();

            // GetTableName() returns table name of TModel
            var query = $"SELECT * FROM {GetTableName()} WHERE {propertyName}='{value}'";

            var output = connection.Query<TModel>(query);
            connection.Dispose();
            return output.FirstOrDefault();

        }
}

и использует его как:

var model = Get(() => foo.FirstProperty);

Однако, если я хочу получить имя и значение из неизвестного числа свойств я делаю это:

public TModel Get(params Expression<Func<object>>[] param)
        using (OracleConnection connection = new OracleConnection(GetConnectionString()))
        {
            connection.Open();

            var query = new StringBuilder();

            query.Append($"SELECT * FROM {GetTableName()} WHERE ");
            for (int i = 0; i < param.Length; i++)
            {
                var propertyName = ((MemberExpression)param[i].Body).Member.Name;

                var value = param[i].Compile()();

                query.Append($"{propertyName} = '{value}'");
                if (i + 1 < param.Length) query.Append(" AND ");
            }

            var output = connection.Query<TModel>(query.ToString());
            connection.Dispose();
            return output.FirstOrDefault();
        }
    }

Но реализация выглядит немного «некрасиво» и многословно:

var model = Get(() => foo.FirstProperty, () => foo.SecondProperty); // and so on

Я мог бы отправить ручное имя свойства + значение, однако, я хотел бы сохранить реализацию как можно более простой и менее многословной.

Есть ли способ упростить это?

1 Ответ

0 голосов
/ 24 февраля 2020

мы можем сократить выражения, сделав Get generi c, задав экземпляр Get foo и изменив выражения на T, object, чтобы они могли принимать foo.

using System;
using System.Linq.Expressions;

namespace SO60378405
{
    static class Program
    {
        static void Main(string[] args)
        {
            var foo = new SomeContainer("hello", 123);
            Get(foo, s => s.SomeString, s => s.SomeInt);
        }
        static void Get<T>(T foo, params Expression<Func<T, object>>[] expressions)
        {
            foreach (var expression in expressions)
            {
                var memberExpression = GetMemberExpression(expression);
                var propertyName = memberExpression.Member.Name;
                var propertyGetter = expression.Compile();
                var propertyValue = propertyGetter(foo);
                Console.WriteLine($"{propertyName} = '{propertyValue}'");
            }
        }
        static MemberExpression GetMemberExpression<T>(Expression<Func<T, object>> expression)
        {
            switch (expression.Body)
            {
                case MemberExpression memberExpression:
                    return memberExpression; //string
                case UnaryExpression unaryExpression when unaryExpression.Operand is MemberExpression operandMemberExpression:
                    return operandMemberExpression; //int, decimal
                default:
                    throw new InvalidOperationException();
            }
        }
    }
    public class SomeContainer
    {
        public string SomeString { get; set; }
        public int SomeInt { get; set; }
        public SomeContainer(string someString, int someInt)
        {
            SomeString = someString;
            SomeInt = someInt;
        }
    }
}
...