【问题标题】:How to filter List<T> with LINQ and Reflection如何使用 LINQ 和反射过滤 List<T>
【发布时间】:2014-10-16 03:58:44
【问题描述】:

我通过反射获取属性,我正在这样做以迭代列表。

private string HandleListProperty(object oldObject, object newObject, string difference, PropertyInfo prop)
{

   var oldList = prop.GetValue(oldObject, null) as IList;
   var newList = prop.GetValue(newObject, null) as IList;

   if (prop.PropertyType == typeof(List<DataModel.ScheduleDetail>))
   {
      List<DataModel.ScheduleDetail> ScheduleDetailsOld = oldList as List<DataModel.ScheduleDetail>;
      List<DataModel.ScheduleDetail> ScheduleDetailsNew = newList as List<DataModel.ScheduleDetail>;

      var groupOldSchedules = ScheduleDetailsOld
                             .GroupBy(x => x.HomeHelpID)
                             .SelectMany(s => s.DistinctBy(d => d.HomeHelpID)
                             .Select(h => new { h.HomeHelpID, h.HomeHelpName }));

      var groupNewSchedules = ScheduleDetailsNew
                             .GroupBy(x => x.HomeHelpID)
                             .SelectMany(s => s.DistinctBy(d => d.HomeHelpID)
                             .Select(h => new { h.HomeHelpID, h.HomeHelpName }));

     var AddedHomeHelp = string.Join(",", groupNewSchedules
                        .Where(x => x.HomeHelpID != null && !groupOldSchedule
                        .Any(y => y.HomeHelpID == x.HomeHelpID))
                        .Select(x => "\"<strong>" + x.HomeHelpName + "\"</strong>"));

     var RemovedHomeHelp = string.Join(",", groupOldSchedules
                          .Where(x => x.HomeHelpID != null && groupNewSchedules
                          .Any(y => y.HomeHelpID != x.HomeHelpID))
                          .Select(x => "\"<strong>"+x.HomeHelpName+"\"</strong>"));

   difference += string.IsNullOrWhiteSpace(RemovedHomeHelp) ? string.Empty : "<strong>HomeHelp</strong> " + RemovedHomeHelp + " Removed<br/>";

   difference += string.IsNullOrWhiteSpace(AddedHomeHelp) ? string.Empty : "<strong>HomeHelp</strong> " + AddedHomeHelp + "Added<br/>";
   }
}

现在我把它变成通用的,因为会有不同类型的列表,我不想把如果条件这样我想写 处理任何类型列表的通用代码。

我想出了这个方法:

private void HandleListProperty(object oldObject, object newObject, string difference, PropertyInfo prop)
{

   var oldList = prop.GetValue(oldObject, null) as IList;
   var newList = prop.GetValue(newObject, null) as IList;

   var ListType = prop.PropertyType; 
   var MyListInstance = Activator.CreateInstance(ListType);

   MyListInstance = oldList;            
}

我能够在MyListInstance 中获取项目,但由于类型将在运行时出现,我不知道如何编写 linq 查询来过滤它们,不知道该怎么做。

【问题讨论】:

  • 请在格式化您的代码方面付出更多努力 - 目前很难阅读,到处都是缩进。
  • 如果我理解你的问题是正确的,我会向这个方法传递一个委托函数来进行过滤。你的具体实现似乎做了非通用的事情,所以你不能真的把它留在那里。
  • @AndreasMüller 没明白你的意思,你能详细说明一下吗?
  • 第一个问题:我认为您的所有列表都没有HomeHelpIdHomeHelpName 属性,是吗?如果没有,您也需要传递这些属性(属性名称)。
  • @RaphaëlAlthaus 当然DataModel.ScheduleDetail 有这些属性

标签: c# linq list generics reflection


【解决方案1】:

您想比较列表。据我了解,您比较的 2 个列表将始终属于同一类型,但一次可能是 2 个 X 列表,另一次可能是 2 个 Y 列表。

LINQ except 方法非常适合这个。默认情况下,它会比较项目是否完全相同,但使用自定义比较器,它可以根据 ID 属性或您想要的任何其他内容进行比较。

您需要确定您认为 2 个项目相等的方式并创建一个自定义比较器来实现 IEqualityComparer&lt;T&gt;,如下所示。

public class CompareSchedules : IEqualityComparer<ScheduleDetail>
{

    public bool Equals(ScheduleDetail x, ScheduleDetail y)
    {
        return x.HomeHelpID == y.HomeHelpID;
    }

    public int GetHashCode(ScheduleDetail obj)
    {
        return obj.HomeHelpID;
    }
}

public static class SuperDuperListComparer
{
    public class ListCompareResults<T>
    {
        public List<T> RemovedItems { get; set; }
        public List<T> AddedItems { get; set; }
    }

    public static ListCompareResults<T> CompareLists<T>(IList<T> list1, IList<T> list2, IEqualityComparer<T> comparer)
    {
        var addedItems = list2.Except(list1, comparer).ToList();
        var removedItems = list1.Except(list2, comparer).ToList();
        return new ListCompareResults<T>
        {
            AddedItems = addedItems,
            RemovedItems = removedItems
        };
    }

    public static ListCompareResults<T> CompareLists<T>(IList<T> list1, IList<T> list2)
    {
        return CompareLists<T>(list1, list2, EqualityComparer<T>.Default);
    }
}

这是一些示例代码。

    [TestMethod]
    public void TestListComparer()
    {
        var list1 = new List<ScheduleDetail> { 
            new ScheduleDetail { HomeHelpID = 1},
            new ScheduleDetail { HomeHelpID = 3}
        };

        var list2 = new List<ScheduleDetail> { 
            new ScheduleDetail { HomeHelpID = 1},
            new ScheduleDetail { HomeHelpID = 5}
        };


        var comparison = SuperDuperListComparer.CompareLists(list1, list2, new CompareSchedules());


    }


    public class ScheduleDetail
    {
        public int HomeHelpID { get; set; }

    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-05
    • 1970-01-01
    • 2011-02-09
    • 1970-01-01
    • 1970-01-01
    • 2014-01-01
    • 1970-01-01
    相关资源
    最近更新 更多