C# 获取多个属性的名称/值

C# 获取多个属性的名称/值,c#,.net,dapper,C#,.net,Dapper,假设我有一个方法,提取属性名称和值: public TModel Get (Expression<Func<object>> param) { using (OracleConnection connection = new OracleConnection(GetConnectionString())) { connection.Open(); var propertyName= ((Me

假设我有一个方法,提取属性名称和值:

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

        }
}
但是,如果我想从未知数量的属性中获取名称和值,我会执行以下操作:

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();
        }
    }
我可以手动发送属性名+值,但是,我希望实现尽可能简单,不太冗长


有什么方法可以简化这一点吗?

我们可以通过使Get泛型、提供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;
        }
    }
}
使用系统;
使用System.Linq.Expressions;
名称空间SO60378405
{
静态类程序
{
静态void Main(字符串[]参数)
{
var foo=newsomecontainer(“hello”,123);
Get(foo,s=>s.SomeString,s=>s.SomeInt);
}
静态void Get(T foo,参数表达式[]表达式)
{
foreach(表达式中的var表达式)
{
var memberExpression=GetMemberExpression(表达式);
var propertyName=memberExpression.Member.Name;
var propertyGetter=expression.Compile();
var propertyValue=propertyGetter(foo);
WriteLine($“{propertyName}='{propertyValue}'”;
}
}
静态MemberExpression GetMemberExpression(表达式)
{
开关(expression.Body)
{
案例成员表达式成员表达式:
返回memberExpression;//字符串
大小写一元表达式一元表达式当一元表达式。操作数为MemberExpression操作数MemberExpression时:
返回操作数MemberExpression;//整数,十进制
违约:
抛出新的InvalidOperationException();
}
}
}
公共类容器
{
公共字符串SomeString{get;set;}
公共int SomeInt{get;set;}
公共SomeContainer(string-someString,int-someInt)
{
SomeString=SomeString;
SomeInt=SomeInt;
}
}
}

如果这是您编写的代码,并且它可以正常工作,并且您希望对代码的各个方面进行审查,那么这可能会更好,但我会在询问之前先查看他们的帮助中心。您这样做是出于速度原因吗?反射已经有了这个功能。@RobertHarvey我这样做是因为我使用的是Oracle数据库和Dapper。但是,Dapper.contrib对oracle不是很友好,我不想手动编写每个查询。因此,我想出了一个想法,有一个方法可以基于给定的属性构建该查询。我的代码片段可以工作,但是,正如我所提到的,它看起来有点“冗长”,特别是对于3+参数,每次我通过属性时都会强制写入“()=>”。我想我们必须看到更多的代码才能找到解决方案。@RobertHarvey我编辑了我的帖子。
var model = Get(() => foo.FirstProperty, () => foo.SecondProperty); // and so on
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;
        }
    }
}