2012-04-03 5 views
6

Gibt es einige "LINQ" Möglichkeit, eine bedingte Auswahl von Daten, d. H. Aus einer anderen Quelle auswählen, wenn die erste leer war? Ein Beispiel ist, wenn Sie eine Baumstruktur von Elementen haben und ein Asset von einem Stamm oder, wenn es leer ist, von seinen Kindern erhalten möchten.Bedingte Auswahl in LINQ (wählen Sie stattdessen, wenn leer)

Ich habe folgendes Beispiel:

IEnumerable<Item> items = ...; 
// Item has a Assets property that returns IEnumerable<Asset> 
// Item has a SubItems property that returns IEnumerable<Item> 
// i.e. other items with assets in them 

// getting assets from a "main" item 
var assets = item.Assets.Where(a => HasRelevantAsset(a)); 

// if there were no relevant assets in the "main" item 
if (!assets.Any()) { 
    // then reselect from "subitems" assets instead 
    assets = item.SubItems.SelectMany(item => 
     item.Assets.Where(a => HasRelevantAsset(a))); 
} 

// HasRelevantAsset(Asset) is a static method that returns 
// true if it is the asset that is needed 
+0

Das scheint eine ziemlich gute Verwendung für die? Operator - 'var Assets = etwas ?? etwas_else'. Es wird nicht funktionieren, aber es wäre schön, wenn es so wäre. – zmbq

Antwort

1

ich die LINQ Weg glauben, ein bisschen hässlich

var assets = item.Any(a=>HaRelevantAsset(a)) ? item.Where(a => HasRelevantAsset(a)) : 
        item.SubItems.SelectMany(item => 
          item.Assets.Where(a => HasRelevantAsset(a))); 

aussehen werde ich für die andere Variante entscheiden würden, Erweiterungsmethode

public static IEnumerable<Asset> SelectRelevantAssets(this Item item) 
{ 
    var assetsInItemFound = false; 
    foreach (var asset in item.Assets) 
    { 
     if (HasRelevantAsset(asset)) 
     { 
      assetsInItemFound = true; 
      yield return asset; 
     } 
    } 
    if (assetsInItemFound) 
    { 
     yield break; 
    } 
    else 
    { 
     foreach (var subItem in item.SubItems)   
      foreach (var asset in subItem.Assets) 
       if (HasRelevantAsset(asset)) 
        yield return asset; 
    } 
} 





Zuerst wollte ich einen rekursiven Aufruf zu SelectRelevantAssets, um zu versuchen, ich denke

if (!assetsInItemFound) 
     { 
      yield break; 
     } 
     else 
     { 
      foreach (var subItem in item.SubItems)   
       foreach (var asset in SelectRelevantAssets(subItem)) 
         yield return asset; 
     } 

sein würde, aber dies beinhaltet die gefundenen Vermögenswerte in der Items Sammlung von Vermögenswerten des SubItem