2014-12-01 3 views
4

У меня есть два общих списка с несколькими свойствами для сравнения, но я хочу, чтобы ключевые идентификаторы были динамическими с помощью List<string>.Переключить два общих списка по динамическим свойствам

Так позволяет сказать, что у нас есть класс:

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

Теперь пользователь может выбрать из пользовательского интерфейса, свойства двух списков этих объектов должны перекрываться так, что выбрана правильная пара. Это сохраняется в List<string>. Например, если строка списка содержит «Имя» и «Цвет1», будут возвращены только те объекты, где «Имя» и «Цвет1» перекрываются.

Я пытался написать функцию, но, к сожалению, я не уверен, какую коллекцию я должен использовать для составления общих списков и как применять имена этих свойств на них? Если имя «идентификаторами» всегда были одинаковыми, это не было бы проблемой, с Linq/Lambda;)

Заранее спасибо

+0

Вы должны прочитать на Reflection. –

+0

Спасибо за ваш ответ, у меня уже есть некоторые полезные функции в моих проектах с отражением, но я не совсем уверен, как использовать его в этом контексте. – kassi

+0

Я думаю, что нашел ответ здесь [Как создать динамическую реализацию равенства, в которой вы можете передать имена свойств для сравнения?] (Http://stackoverflow.com/questions/17015566/how-do-you-create -a-dynamic-equal-implementation-where-you-can-pass-in-the-pr) – kassi

ответ

2

Вы должны использовать отражение для этого. Это работает:

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(); 
+0

Спасибо большое! – kassi

+1

@kassi: обратите внимание, что я [отредактировал] (http://stackoverflow.com/posts/27229397/revisions) свой ответ и отменил предложение Join-Clause в запросе 'props'. В противном случае он не учитывает регистр. –

 Смежные вопросы

  • Нет связанных вопросов^_^