通过KeyAttribute和属性值查找两个列表的交集

时间:2017-11-20 16:11:41

标签: c# linq reflection

我希望通过反映KeyAttribute属性值来获取两个列表的交集:

这给了我主键属性(对于复合):

IEnumerable<PropertyInfo> keys = typeof(T).GetProperties().Where(prop => prop.IsDefined(typeof(KeyAttribute)));

现在,我如何找到两个列表的交集?

private static ICollection<T> Except<T>(this ICollection<T> source, ICollection<T> toIgnore)
{
    IEnumerable<PropertyInfo> keys = typeof(T).GetProperties().Where(prop => prop.IsDefined(typeof(KeyAttribute)));
    return source.Where(x => ???);
}

我想要的最终用例是:var result = firstList.Except(second); 它必须返回第一个列表中与第二个列表不匹配键属性值的项目。

编辑:

我可以做类似的事情,但它只适用于一个属性

public static IEnumerable<T> Except<T, TKey>(this IEnumerable<T> items, IEnumerable<T> other, Func<T, TKey> getKey)
{
    return from item in items
            join otherItem in other on getKey(item) equals getKey(otherItem) into tempItems
            from temp in tempItems.DefaultIfEmpty()
            where ReferenceEquals(null, temp) || temp.Equals(default(T))
            select item;
}

private static int GetPrimaryKey<T>(T item)
{
    foreach (PropertyInfo property in item.GetType().GetProperties())
    {
        KeyAttribute attr = property.GetCustomAttribute<KeyAttribute>();
        if (attr != null)
        {
            return int.Parse(property.GetValue(item).ToString());
        }
    }
    return -1;
}

1 个答案:

答案 0 :(得分:1)

根据您的实际用例,您可以考虑构建表达式树来执行一些缓存。无论如何,这是一个直接的反射解决方案(https://dotnetfiddle.net/zfK1SU):

public class Program
{
    public static void Main(string[] args)
    {
        var l1 = new List<ClassB>()
        {
            new ClassB() { KeyOne = 3, KeyTwo = 0 },
            new ClassB() { KeyOne = 5, KeyTwo = 0 },
            new ClassB() { KeyOne = 3, KeyTwo = 1 },
            new ClassB() { KeyOne = 5, KeyTwo = 1 }
        };

        var l2 = new List<ClassB>()
        {
            new ClassB() { KeyOne = 5, KeyTwo = 0 }
        };

        var x = Except(l1, l2).ToList();
        x.Dump();

    }

    public static IEnumerable<T> Except<T>(IEnumerable<T> items, IEnumerable<T> other)
    {
        var keyProps = typeof(T).GetProperties().Where(prop => prop.IsDefined(typeof(KeyAttribute))).ToList();

        return items.Where(x => !other.Any(o => keyProps.All(prop => prop.GetValue(x).Equals(prop.GetValue(o)))));
    }
}


public class ClassB
{
    [Key]
    public int KeyOne { get; set; }

    [Key]
    public int KeyTwo { get; set; }

    public string NoKey { get; set; }
}