【问题标题】:Filter a Generic list using LINQ using a PropertyName as a string literal - Using dynamics使用 LINQ 过滤通用列表,使用 PropertyName 作为字符串文字 - 使用动态
【发布时间】:2016-06-03 06:35:07
【问题描述】:

我想知道这种方法是否可以做得更好。我需要过滤作为字符串传入的成员名称上的通用列表。我的想法是将通用列表转换为动态列表,然后将 expandoObject 转换为 Dictionary 并检查成员名称是否存在。最后,使用 JsonSerializer 将动态列表转换回通用列表。您对更好的实施有何想法?反射?动态 LINQ(Scott Guthrie 在 2008 年做了一些工作)?表达式树?

        public static IEnumerable<T> FilterListByStringPropertyName<T>(this IEnumerable<T> genericList, int? enumId, string enumFieldName)
    {
        if (string.IsNullOrEmpty(enumFieldName))
        {
            throw new NullReferenceException("FilterByEnum: enumFieldName cannot be empty");
        }

        if (enumId == null)
        {
            //skip method as no filtering needed
            return genericList;
        }

        if (genericList.Count() == 0)
        {
            return genericList;
        }

        List<T> @return = new List<T>();
        List<dynamic> dynamicList = new List<dynamic>();

        //fill the dynamic list from generic list
        foreach (var genericItem in genericList)
            dynamicList.Add(genericItem.ToDynamic());

        var first = dynamicList.FirstOrDefault();

        //initialise filteredDynamicList
        IEnumerable<dynamic> filteredDynamicList = dynamicList;

        if (enumId != null)
        {
            //ExpandoObject implements IDictionary<string, object>, so cast as that to check what the fields are
            if (!((IDictionary<string, object>)first).ContainsKey(enumFieldName))
            {
                throw new KeyNotFoundException(string.Format("{0} is not a member of {1}", enumFieldName, genericList.GetType().GetGenericArguments()[0]));
            }

            //filter by the AddressStatus enum (as int)
            filteredDynamicList = dynamicList.Where(a => (int)((IDictionary<string, object>)a)[enumFieldName] == enumId.Value);
        }

        //convert from dynamic back to to generic
        var json = Newtonsoft.Json.JsonConvert.SerializeObject(filteredDynamicList);
        @return = Newtonsoft.Json.JsonConvert.DeserializeObject<List<T>>(json);

        return @return;
    }

【问题讨论】:

    标签: c# linq generics dynamic


    【解决方案1】:

    先试试看能不能找到强类型解决方案(Expression/Func),然后再尝试其他方法(Reflection)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    
    namespace ConsoleApplication9
    {
    class Program
    {
        static void Main(string[] args)
        {
    
            var customers = Enumerable.Range(1, 10).Select(c => new Customer() { Id = c, Name = "Customer " + c });
    
            var filteredCustomers = StronglyNameFilter(customers, c => c.Id == 1);
            var filteredCustomers2 = StronglyNameFilter(customers, c => c.Name == "Customer 1");
    
            var filteredCustomers3 = ReflectionFilter(customers, "Id", 1);
            var filteredCustomers4 = ReflectionFilter(customers, "Name", "Customer 1");
    
            Console.ReadLine();
        }
    
        private static IEnumerable<T> StronglyNameFilter<T>(IEnumerable<T> collection, Func<T, bool> filter)
        {
            return collection.Where(filter).ToList();
        }
        private static IEnumerable<T> ReflectionFilter<T>(IEnumerable<T> collection, string property, object value)
        {
            if (collection.Count() == 0)
                return new List<T>();
            PropertyInfo pInfo = collection.First().GetType().GetProperty(property);
    
            return collection.Where(c => object.Equals(pInfo.GetValue(c), value)).ToList();
        }
    }
    
    public class Customer
    {
        public string Name { get; set; }
        public int Id { get; set; }
    }
    }
    

    【讨论】:

    • 优秀。比我想象的要简单!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-11-18
    • 2015-10-30
    • 1970-01-01
    • 2017-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多