【问题标题】:Building a dynamic linq Func to return a string构建动态 linq Func 以返回字符串
【发布时间】:2016-09-05 07:31:00
【问题描述】:

我正在尝试找出 IQueryable 如何通过动态选择对象作为字符串来构建 csv 文件。

例如:

我读过这篇关于动态选择 T 属性的文章 ...

LINQ : Dynamic select

这将允许我做这样的事情......

var data = new List<T> { items };
            var fields = new string[] { "Field1", "Field2", "Field3" };
            // build row strings
            var rows = set.Select(BuildRowObjectExpression<T, ProjectionOfT>(fields))
                .Select(i => Serialise<ProjectionOfT>(i));


        string Serialise<T>(T i, string separator)
        {
            var properties = typeof(T).GetProperties();
            var values = new List<string>();
            foreach (var p in properties)
                values.Add(p.GetValue(i).ToString());

            return string.Join(separator, values);
        }

        Func<T, Tout> BuildRowObjectExpression<T, Tout>(string[] fields)
        {
            // input parameter "o"
            var xParameter = Expression.Parameter(typeof(T), "o");

            // new statement "new Data()"
            var xNew = Expression.New(typeof(T));

            // create initializers
            var bindings = fields.Select(o => {

                    // property "Field1"
                    var mi = typeof(T).GetProperty(o);

                    // original value "o.Field1"
                    var xOriginal = Expression.Property(xParameter, mi);

                    // set value "Field1 = o.Field1"
                    return Expression.Bind(mi, xOriginal);
                }
            );

            // initialization "new T { Field1 = o.Field1, Field2 = o.Field2 }"
            var xInit = Expression.MemberInit(xNew, bindings);

            // expression "o => new T { Field1 = o.Field1, Field2 = o.Field2 }"
            var lambda = Expression.Lambda<Func<T, string>>(xInit, xParameter);

            // compile to Func<T, string>
            return lambda.Compile();
        }

我想知道的是:

如何将其构建为一个表达式/函数,我可以将其与 IQueryable 一起使用来执行类似的操作

// this would build me a string array from the specified properties 
// in a collection of T joining the values using the given separator 
var results = data.Select(i => BuildString(fields, "|")).ToArray();

理想情况下,我希望将它与实体集一起使用。

【问题讨论】:

    标签: c# linq dynamic linq-to-entities


    【解决方案1】:

    字符串转换/连接不是数据库作业。您最好将这两个部分分开 - 数据库查询中的数据检索和内存查询中的数据转换。

    例如,您可以使用以下自定义扩展方法:

    public static class Extensions
    {
        public static IQueryable<T> Select<T>(this IQueryable source, string[] fields)
        {
            var parameter = Expression.Parameter(source.ElementType, "o");
            var body = Expression.MemberInit(
                Expression.New(typeof(T)),
                fields.Select(field => Expression.Bind(
                    typeof(T).GetProperty(field),
                    Expression.PropertyOrField(parameter, field))
                )
            );
            var selector = Expression.Lambda(body, parameter);
            var expression = Expression.Call(
                typeof(Queryable), "Select", new[] { parameter.Type, body.Type },
                source.Expression, Expression.Quote(selector)
            );
            return source.Provider.CreateQuery<T>(expression);
        }
    
        public static IEnumerable<string> Serialize<T>(this IEnumerable<T> source, string separator)
        {
            var properties = typeof(T).GetProperties();
            return source.Select(item => string.Join(separator, properties.Select(property => property.GetValue(item))));
        }
    }
    

    喜欢这个

    var results = db.Data.Select<ProjectionOfT>(fields).Serialize("|");
    

    如果你想避免 ProjectionOfT 类,没有简单的方法,因为它需要动态生成运行时类,所以你最好求助于 System.Linq.Dynamic 包。

    【讨论】:

    • 呸,它并没有解决我的实际问题,但我不认为这是一个措辞恰当的问题,也就是说它确实解决了问题中提出的问题。谢谢 :)
    猜你喜欢
    • 1970-01-01
    • 2012-12-17
    • 1970-01-01
    • 2010-11-08
    • 1970-01-01
    • 2018-02-07
    • 1970-01-01
    • 1970-01-01
    • 2011-09-19
    相关资源
    最近更新 更多