按动态属性与两个泛型列表相交

本文关键字:泛型 两个 列表 属性 动态 | 更新日期: 2023-09-27 18:32:32

我有两个通用列表,其中包含一些要比较的属性,但我希望键标识符是动态的List<string>

因此,假设我们有这样的类:

class A
{
    string Name { get; set; }
    string Color1 { get; set; }
    string Color2 { get; set; }
    string Length { get; set; }
}

用户现在可以从用户界面中选择这些对象的两个列表的属性需要重叠,以便选择正确的对。这存储在List<string> 中。例如,如果列表字符串包含"Name"和"Color1",则仅返回"Name"和"Color1"重叠的对象。

正在尝试编写一个函数,但不幸的是,我不确定我应该将泛型列表投射到哪个集合以及如何在这些集合上应用属性的名称?如果"识别器"的名称始终相同,那么Linq/Lambda;)就不会有问题

提前致谢

按动态属性与两个泛型列表相交

为此,您需要使用反射。这有效:

public class A
{
    public string Name { get; set; }
    public string Color1 { get; set; }
    public string Color2 { get; set; }
    public string Length { get; set; }
    public static IEnumerable<A> Intersecting(IEnumerable<A> input, List<string> propertyNames)
    { 
        if(input == null)
            throw new ArgumentNullException("input must not be null ", "input");
        if (!input.Any() || propertyNames.Count <= 1)
            return input;
        var properties = typeof(A).GetProperties();
        var validNames = properties.Select(p => p.Name);
        if (propertyNames.Except(validNames, StringComparer.InvariantCultureIgnoreCase).Any())
            throw new ArgumentException("All properties must be one of these: " + string.Join(",", validNames), "propertyNames");
        var props = from prop in properties
                    join name in validNames.Intersect(propertyNames, StringComparer.InvariantCultureIgnoreCase)
                    on prop.Name equals name
                    select prop;
        var allIntersecting = input
            .Select(a => new { 
                Object = a,
                FirstVal = props.First().GetValue(a, null),
                Rest = props.Skip(1).Select(p => p.GetValue(a, null)),
            })
            .Select(x => new { 
                x.Object, x.FirstVal, x.Rest,
                UniqueValues = new HashSet<object>{ x.FirstVal }
            })
            .Where(x => x.Rest.All(v => !x.UniqueValues.Add(v)))
            .Select(x => x.Object);
        return allIntersecting;
    }
}

示例数据:

var aList = new List<A> { 
    new A { Color1 = "Red", Length = "2", Name = "Red" }, new A { Color1 = "Blue", Length = "2", Name = "Blue" },
    new A { Color1 = "Red", Length = "2", Name = "A3" }, new A { Color1 = "Blue", Length = "2", Name = "A3" },
    new A { Color1 = "Red", Length = "3", Name = "Red" }, new A { Color1 = "Blue", Length = "2", Name = "A6" },
};
var intersecting = A.Intersecting(aList, new List<string> { "Color1", "Name" }).ToList();