2017-01-30 3 views
0

Допустим, у меня есть следующий объект:Сформировать все возможные комбинации объектов из другого объекта

public class Foo 
    { 
     public int? Prop1 { get; set; } 
     public int? Prop2 { get; set; } 
     public int? Prop3 { get; set; } 
    } 

инициализируется так:

var test = new Foo(){ 
    Prop1 = 10, 
    Prop2 = 20, 
    Prop3 = 30 
} 

Я хотел бы, чтобы создать список всех возможных комбинаций эти атрибуты. Следующий список был бы возможный результат (в основном список всех возможных комбинаций):

List[0] = new Foo{Prop1 = 10, Prop2 = null, Prop3 = null}; 
List[1] = new Foo{Prop1 = null, Prop2 = 20, Prop3 = null} 
List[2] = new Foo{Prop1 = null, Prop2 = null, Prop3 = 30}; 
List[3] = new Foo{Prop1 = 10, Prop2 = 20, Prop3 = null}; 
List[4] = new Foo{Prop1 = 10, Prop2 = null, Prop3 = 30}; 
List[5] = new Foo{Prop1 = null, Prop2 = 20, Prop3 = 30}; 
List[6] = new Foo{Prop1 = 10, Prop2 = 20, Prop3 = 30}; 

Я думал, с помощью LINQ или отражения, чтобы попытаться управлять всеми свойствами и делать .... что-то. Конечно, это можно сделать с помощью большого количества ручных добавлений, получая все комбинации вручную и заканчивая длинным кодом, но я уверен, что есть более простой способ добиться этого, поэтому ... любая помощь будет оценена по достоинству.

Благодаря

+1

Является ли порядок комбинаций важным? –

+0

Что вы имеете в виду как порядок комбинаций? если вы имеете в виду, что мне нужен этот список [0] из примера в позиции 0, нет, это не важно, это просто пример. Значения внутри являются свойствами объекта, поэтому вы не можете их изменить. – Thal

+0

Да Я имел в виду порядок элементов в конечном списке - мой ответ генерирует те же комбинации, что и ваш пример выше, но в другом порядке. –

ответ

2

Это отвратительный и рискованной метод будет генерировать список комбинаций для произвольного объекта:

public List<T> CombinationsOf<T>(T template) 
{ 
    var properties = typeof(T).GetProperties().Where(prop => prop.CanRead && prop.CanWrite).ToArray(); 
    var combinations = 1 << properties.Length; 
    var result = new List<T>(combinations - 1); 
    for (var i = 1; i < combinations; i++) 
    { 
     var instance = (T)Activator.CreateInstance(typeof(T)); 
     var bits = i; 
     for (var p = 0; p < properties.Length; p++) 
     { 
      properties[p].SetValue(instance, (bits % 2 == 1) ? properties[p].GetValue(template) : properties[p].PropertyType.IsValueType ? Activator.CreateInstance(properties[p].PropertyType) : null); 
      bits = bits >> 1; 
     } 

     result.Add(instance); 
    } 

    return result; 
} 

Использование:

var result = CombinationsOf(new Foo { Prop1 = 10, Prop2 = 20, Prop3 = 30 }); 

Вы можете изменить внешнее инициализатор цикла до i = 0, если вы хотите «отсутствующий» com бинация будет все значения по умолчанию.

Предупреждение: Этот код опасно - это:

  • Устанавливает частные свойства, которые могут нарушить внутреннее состояние.
  • Звонит разработчикам и получателям, которые могут запускать код, вызывающий побочные эффекты.
  • будет производить неправильный результат, если есть более чем 31 свойства, как < < оператор завернуть, и вы будете получать неверное число комбинаций ...
  • ... если вы не попали в OutOfMemoryException, что это вероятно, произойдет с c. 25 свойств и выше благодаря огромному количеству комбинаций.
+0

Я могу понять ** отвратительный **, но почему вы говорите ** опасный **? – Enigmativity

+1

Очень хорошее объяснение. Может быть, вы должны положить это в ответ? – Enigmativity

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