Могу ли я условно создать IEnumerable с помощью LINQ? - PullRequest
2 голосов
/ 19 мая 2011

Мне нужен следующий код:

List<Obj> coll = new List<Obj>();

if (cond1) coll.Add(new Obj { /*...*/ });
if (cond2) coll.Add(new Obj { /*...*/ });
if (cond3) coll.Add(new Obj { /*...*/ });

Есть ли способ использовать для этого LINQ или инициализаторы коллекций?

РЕДАКТИРОВАТЬ:

Причина, по которой я хочу использовать инициализатор коллекции, заключается в том, что у меня есть дерево объектов, которое я полностью инициализирую инициализаторами и LINQ.Это единственное место, которое не следует этому принципу.

var myobj = new MyBigObj 
{
    Prop1 = from .. select ..,
    Prop2 = from .. select ..,
    ...
    Prop3 = new MySmallerObj 
    {
      PropSmall1 = from .. select ..,
      PropSmall2 = from .. select ..,
      ...
    }
};

И теперь это просто не вписывается в мою схему:

List<Obj> coll = new List<Obj>();

if (cond1) coll.Add(new Obj { /*...*/ });
if (cond2) coll.Add(new Obj { /*...*/ });
if (cond3) coll.Add(new Obj { /*...*/ });

myobj.Prop4 = coll;

Конечно, я мог бы поставить этот кодв отдельной функции, которая возвращает IEnumerable и вызывает его ..:)

EDIT2:

Похоже, мне нужно кодировать какой-то метод расширения, который я бы назвал так:

new Obj[0]
.ConditionalConcat(cond1, x=>new Obj { /*...*/ })
.ConditionalConcat(cond2, x=>new Obj { /*...*/ })
.ConditionalConcat(cond3, x=>new Obj { /*...*/ })

Ответы [ 3 ]

5 голосов
/ 19 мая 2011

Один довольно ужасный вариант:

var conditions = new[] { cond1, cond2, cond3 };
var values = new[] { new Obj {...}, // First value
                     new Obj {...}, // Second value
                     new Obj { ...} // Third value
                   };

var list = conditions.Zip(values, (condition, value) => new { condition, value })
                     .Where(pair => pair.condition)
                     .Select(pair => pair.value)
                     .ToList();

Это не совсем проще, чем оригинальный код;) (А также он безусловно создает все значения - это только условно включая их в коллекцию.)

РЕДАКТИРОВАТЬ: альтернатива, которая создает значения только тогда, когда это необходимо:

var conditions = new[] { cond1, cond2, cond3 };
var valueProviders = new Func<Obj>[] { 
    () => new Obj {...}, // First value
    () => new Obj {...}, // Second value
    () => new Obj { ...} // Third value
};


var list = conditions.Zip(valueProviders,
                          (condition, provider) => new { condition, provider })
                     .Where(pair => pair.condition)
                     .Select(pair => pair.provider())
                     .ToList();

РЕДАКТИРОВАТЬ: Учитывая ваш запрошенный синтаксис, это довольнопростой вариант:

new List<Obj>()
    .ConditionalConcat(cond1, x=>new Obj { /*...*/ })
    .ConditionalConcat(cond2, x=>new Obj { /*...*/ })
    .ConditionalConcat(cond3, x=>new Obj { /*...*/ })

с методом расширения:

public static List<T> ConditionalConcat<T>(this List<T> source,
                                           bool condition,
                                           Func<T> provider)
{
    if (condition)
    {
        source.Add(provider);
    }
    return source;
}
2 голосов
/ 19 мая 2011

Если ваши условия зависят от одного объекта состояния (или чего-то, что может быть уменьшено до), вы можете создать метод с использованием yield, например, следующим образом:

IEnumerable<Obj> GetElemets(MyStatus currentStatus)
{
    if(currentStatus.Prop1 == "Foo")
       yield return new Obj {...};
    if(currentStatus.IsSomething())
       yield return new Obj {...};
    if(currentStatus.Items.Any())
       yield return new Obj {...};
    // etc...
    yield break;
}

Таким образом, вы отделитеIEnumerable<Obj> логика генерации, от потребительской логики.

0 голосов
/ 26 марта 2015

Старый вопрос, но здесь есть другой подход с использованием операторов тернери ? :,. Concat() и Enumerable.Empty<T>()

var range1 = Enumerable.Range(1,10);
var range2 = Enumerable.Range(100,10);
var range3 = Enumerable.Range(1000,10);

var flag1 = true;
var flag2 = false;
var flag3 = true;

var sumOfCollections = (flag1 ? range1 : Enumerable.Empty<int>())
.Concat(flag2 ? range2 : Enumerable.Empty<int>())
.Concat(flag3 ? range3 : Enumerable.Empty<int>());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...