合并可能为空的LINQ查询结果

时间:2012-05-30 15:00:27

标签: c# linq coalesce null-coalescing-operator

我使用Linq从4个级联下拉菜单中返回ID。

用户可能已从1个或所有菜单中选择了1个或多个值。从用户选择中,我然后查询DataTable的文本列以获取代表ID。

如果用户从第4(和最低级别)下拉菜单中进行选择,那么他们将从上述所有选项中进行选择。

如果用户从菜单1中选择“X”,从菜单2中选择“Y”,而在其他人中没有任何内容我希望看到results1表示[Col_1]中存在“X”的10行,然后将在results2中查询5行,其中“Col”中存在“Y”。

修改 守则(基本形式)

var results1 = 
    from a in dt.AsEnumerable()
    where stringArray1.Contains([Col1])
    select a;


var results2 = 
    from a in results1
    where stringArray2.Contains([Col2])
    select a;

var results3 = 
    from a in results2
    where stringArray3.Contains([Col3])
    select a;

var results4 = 
    from a in results3
    where stringArray4.Contains([Col4])
    select a;

var results = results4 ?? results3 ?? results2 ?? results1;

results4取决于results3上的results3results2上的results2以及results1results4 - 2的结果。

可能var results = results4 ?? results3 ?? results2 ?? results1; 是空的,因此我想知道我是否可以将这些合并为最终变量,例如:

Operator '??' cannot be applied to operands of type 'System.Collections.Generic.IEnumerable<AnonymousType#4>'

这引发了错误:

{{1}}

有没有人有任何狡猾的想法如何解决这个问题?我尽量不写很长的啰嗦代码,处理每一个可能的结果。

提前谢谢大家(希望这个问题有道理!)

CM

3 个答案:

答案 0 :(得分:5)

因此,根据您使用的查询,结果都不会是null。其中一些可能是空的,但它们不会是null。这意味着??运算符将不会执行任何有用的操作。

你希望这个表现如何?你想说,“如果这个结果是空的,那就用另一个吗?”为此使用我在下面写的方法。

public static IEnumerable<T> Coalesce<T>(IEnumerable<T> first, IEnumerable<T> second)
{
  if(first == null || !first.Any())
  {
    return second;
  }
  else
  {
    return first;
  }
}

然后可以用作:

Coalesce(results4, Coalesce(results3, Coalesce(results2, results1)));

结果是“返回result4,除非它是空的。如果它是空的,则返回results3。如果results3为空,则返回results2,如果{{1}是空的返回results2。“

如果您认为自己足够使用它,可以将其作为扩展方法。它会使它更漂亮,但也会使所有其他results1的智能感知混乱,所以它可能不值得。

答案 1 :(得分:0)

如果您不想编写冗长的代码,可以

public static IEnumerable<T> SomeOrAll<T>(
    this IEnumerable<T> source, 
    Predicate<T> where)
{
    var results = source.Where(where)
    return results.Any() ? results : source;
}

var results = dt.AsEnumerable()
    .SomeOrAll(a => a.stringArray4.Contains([Col4]))
    .SomeOrAll(a => a.stringArray3.Contains([Col3]))
    .SomeOrAll(a => a.stringArray2.Contains([Col2]))
    .SomeOrAll(a => a.stringArray1.Contains([Col1]));

但是,我怀疑,如果你退后一步,你可以做点别的事。如果人们经常需要这种扩展,那么它可能已经存在(也许。)

答案 2 :(得分:0)

我会重写查询以解决问题,而不是在事后处理它。

public List<string> FilterResults(string first, string second, string third, string fourth)
{
    var query = from a in dt.AsEnumerable()
                let firsts = first != null ? a.Where( x => x.stringArray1.Contains( first ) ) : null,
                let seconds = second != null ? firsts.Where( x => x.stringArray2.Contains( second ) ) : null,
                let thirds = third != null ? seconds.Where( x => x.stringArray3.Contains( third ) ) : null,
                let fourths = fourth != null ? thirds.Where( x => x.stringArray4.Contains( fourth ) ) : null
                select fourths ?? thirds ?? seconds ?? firsts;
    return query.ToList();
}

虽然我没有运行这个VS,但总的想法应该会遇到。