Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/257.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何实现;MinOrDefault";在林克?_C#_Linq - Fatal编程技术网

C# 如何实现;MinOrDefault";在林克?

C# 如何实现;MinOrDefault";在林克?,c#,linq,C#,Linq,我正在从linq表达式生成一个十进制值列表,我想要最小的非零值。但是,linq表达式完全有可能导致空列表 这将引发一个异常,没有任何错误可以应对这种情况 decimal result = (from Item itm in itemList where itm.Amount > 0 select itm.Amount).Min(); 如果列表为空,如何将结果设置为0 decimal? result = (from I

我正在从linq表达式生成一个十进制值列表,我想要最小的非零值。但是,linq表达式完全有可能导致空列表

这将引发一个异常,没有任何错误可以应对这种情况

decimal result = (from Item itm in itemList
                  where itm.Amount > 0
                  select itm.Amount).Min();
如果列表为空,如何将结果设置为0

decimal? result = (from Item itm in itemList
                  where itm.Amount != 0
                  select (decimal?)itm.Amount).Min();
请注意转换为
十进制?
。如果没有异常,您将得到一个空结果(只需在事后处理它-我主要说明如何停止异常)。我还使用了“非零”
=
而不是

您想要的是:

IEnumerable<double> results = ... your query ...

double result = results.MinOrDefault();
但是,
System.Linq
中有一些功能将产生相同的结果(以稍微不同的方式):

如果
results
序列不包含任何元素,
DefaultIfEmpty()
将生成一个包含一个元素的序列,即
default(T)
,您随后可以调用
Min()

如果
default(T)
不是您想要的,那么您可以使用以下命令指定自己的默认值:

double myDefault = ...
double result = results.DefaultIfEmpty(myDefault).Min();

现在,这太好了

此方法将从
项目列表
返回单个最小的
金额
值。理论上,这应该避免多次往返数据库

decimal? result = (from Item itm in itemList
                  where itm.Amount > 0)
                 .Min(itm => (decimal?)itm.Amount);
由于我们使用的是可为null的类型,因此不再导致null引用异常


通过在调用
Min
之前避免使用执行方法,例如
Any
,我们应该只访问一次数据库

,就少量代码只执行一次而言,最简单的方法是,如前所述:

decimal result = (from Item itm in itemList
  where itm.Amount > 0
    select itm.Amount).DefaultIfEmpty().Min();
itm.Amount
转换为
decimal?
并获得
Min
,如果我们希望能够检测到这种空状态,这是最简单的

但是,如果您希望实际提供一个
MinOrDefault()
,那么我们当然可以从以下内容开始:

public static TSource MinOrDefault<TSource>(this IQueryable<TSource> source, TSource defaultValue)
{
  return source.DefaultIfEmpty(defaultValue).Min();
}

public static TSource MinOrDefault<TSource>(this IQueryable<TSource> source)
{
  return source.DefaultIfEmpty(defaultValue).Min();
}

public static TResult MinOrDefault<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector, TSource defaultValue)
{
  return source.DefaultIfEmpty(defaultValue).Min(selector);
}

public static TResult MinOrDefault<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector)
{
  return source.DefaultIfEmpty().Min(selector);
}
所以,虽然一开始就不那么整洁,但从那时起就更整洁了

但是等等!还有更多

假设您使用EF并希望使用
async
支持。容易做到:

public static Task<TSource> MinOrDefaultAsync<TSource>(this IQueryable<TSource> source, TSource defaultValue)
{
  return source.DefaultIfEmpty(defaultValue).MinAsync();
}

public static Task<TSource> MinOrDefaultAsync<TSource>(this IQueryable<TSource> source)
{
  return source.DefaultIfEmpty(defaultValue).MinAsync();
}

public static Task<TSource> MinOrDefaultAsync<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector, TSource defaultValue)
{
  return source.DefaultIfEmpty(defaultValue).MinAsync(selector);
}

public static Task<TSource> MinOrDefaultAsync<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector)
{
  return source.DefaultIfEmpty().MinAsync(selector);
}
现在让我们先从更一般的情况开始:

public static TSource MinOrDefault<TSource>(this IEnumerable<TSource> source, TSource defaultValue)
{
  if(default(TSource) == null) //Nullable type. Min already copes with empty sequences
  {
    //Note that the jitter generally removes this code completely when `TSource` is not nullable.
    var result = source.Min();
    return result == null ? defaultValue : result;
  }
  else
  {
    //Note that the jitter generally removes this code completely when `TSource` is nullable.
    var comparer = Comparer<TSource>.Default;
    using(var en = source.GetEnumerator())
      if(en.MoveNext())
      {
        var currentMin = en.Current;
        while(en.MoveNext())
        {
          var current = en.Current;
          if(comparer.Compare(current, currentMin) < 0)
            currentMin = current;
        }
        return currentMin;
      }
  }
  return defaultValue;
}
依此类推,
long
float
double
decimal
,以匹配
可枚举
提供的
Min()
集合。这就是T4模板有用的地方


最后,对于各种类型,我们的
MinOrDefault()
实现的性能与我们所希望的一样。在一次使用它时当然不是“整洁”的(同样,只使用
DefaultIfEmpty().Min()
),但是如果我们发现自己经常使用它,那么我们就非常“整洁”,因此我们有一个很好的库可以重用(或者实际上,在StackOverflow上粘贴到答案中…。

如果itemList不可为null(其中DefaultIfEmpty给出0)如果希望null作为潜在输出值,也可以使用lambda语法:

decimal? result = itemList.Where(x => x.Amount != 0).Min(x => (decimal?)x);

有趣。我不知道这将如何避免一个空列表,但我会尝试一下:
decimal?结果=(新小数?[0]).Min()给出
null
,然后可能使用??0以获得所需的结果?它肯定有效。我刚刚构建了一个单元测试来进行测试,但是我需要花5分钟的时间来弄清楚为什么select的结果是一个空值而不是一个空列表(我的sql背景可能让我感到困惑)。谢谢。@Lette,如果我将其更改为:decimal result1=……Min()??0; 这也行得通,所以谢谢你的输入。@Christofferette我只想要一个T的空列表,所以我也使用了Any()和Min()。谢谢@AdRiangMar:BTW,您是否考虑使用A作为默认值?这里提到的MyOrrRebug实现将迭代枚举两次。这对于内存中的集合并不重要,但对于LINQ to Entity或惰性“yield return”构建的可枚举项,这意味着两次往返数据库或两次处理第一个元素。我更喜欢results.DefaultIfEmpty(myDefault).Min()解决方案。查看
DefaultIfEmpty
的源代码,它确实实现得很智能,仅当存在使用
的元素时,序列的转发才会返回
s.@jAndChips,您引用的格式是
DefaultIfEmpty
,该格式采用
IEnumerable
。如果在
IQueryable
上调用它,例如在数据库操作中调用它,那么它不会返回单例序列,而是生成适当的
MethodCallExpression
,因此结果查询不需要检索所有内容。这里建议的
EnumerableExtensions
方法确实存在这个问题。您怎么会认为在接受的答案中使用
Select
会多次执行查询?接受的答案将导致一个DB调用。没错,
Select
是一个延迟方法,不会导致执行。我已经把这些谎言从我的回答中去掉了。参考资料:亚当·弗里曼(Adam Freeman)的《Pro ASP.NET MVC4》如果你真的想在确保没有浪费方面保持乐观,请看我刚刚发布的答案。
public static Task<TSource> MinOrDefaultAsync<TSource>(this IQueryable<TSource> source, TSource defaultValue)
{
  return source.DefaultIfEmpty(defaultValue).MinAsync();
}

public static Task<TSource> MinOrDefaultAsync<TSource>(this IQueryable<TSource> source)
{
  return source.DefaultIfEmpty(defaultValue).MinAsync();
}

public static Task<TSource> MinOrDefaultAsync<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector, TSource defaultValue)
{
  return source.DefaultIfEmpty(defaultValue).MinAsync(selector);
}

public static Task<TSource> MinOrDefaultAsync<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector)
{
  return source.DefaultIfEmpty().MinAsync(selector);
}
public static TSource? MinOrDefault<TSource>(this IEnumerable<TSource?> source, TSource? defaultValue) where TSource : struct
{
  return source.Min() ?? defaultValue;
}
public static TSource? MinOrDefault<TSource>(this IEnumerable<TSource?> source) where TSource : struct
{
  return source.Min();
}
public static TResult? Min<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult?> selector, TResult? defaultValue) where TResult : struct
{
  return source.Min(selector) ?? defaultValue;
}
public static TResult? Min<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult?> selector) where TResult : struct
{
  return source.Min(selector);
}
public static TSource MinOrDefault<TSource>(this IEnumerable<TSource> source, TSource defaultValue)
{
  if(default(TSource) == null) //Nullable type. Min already copes with empty sequences
  {
    //Note that the jitter generally removes this code completely when `TSource` is not nullable.
    var result = source.Min();
    return result == null ? defaultValue : result;
  }
  else
  {
    //Note that the jitter generally removes this code completely when `TSource` is nullable.
    var comparer = Comparer<TSource>.Default;
    using(var en = source.GetEnumerator())
      if(en.MoveNext())
      {
        var currentMin = en.Current;
        while(en.MoveNext())
        {
          var current = en.Current;
          if(comparer.Compare(current, currentMin) < 0)
            currentMin = current;
        }
        return currentMin;
      }
  }
  return defaultValue;
}
public static TSource MinOrDefault<TSource>(this IEnumerable<TSource> source)
{
  var defaultValue = default(TSource);
  return defaultValue == null ? source.Min() : source.MinOrDefault(defaultValue);
}
public static TResult MinOrDefault<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector, TResult defaultValue)
{
  return source.Select(selector).MinOrDefault(defaultValue);
}
public static TResult MinOrDefault<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
{
  return source.Select(selector).MinOrDefault();
}
public static int MinOrDefault(this IEnumerable<int> source, int defaultValue)
{
  using(var en = source.GetEnumerator())
    if(en.MoveNext())
    {
      var currentMin = en.Current;
      while(en.MoveNext())
      {
        var current = en.Current;
        if(current < currentMin)
          currentMin = current;
      }
      return currentMin;
    }
  return defaultValue;
}
public static int MinOrDefault(this IEnumerable<int> source)
{
  return source.MinOrDefault(0);
}
public static int MinOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, int> selector, int defaultValue)
{
  return source.Select(selector).MinOrDefault(defaultValue);
}
public static int MinOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, int> selector)
{
  return source.Select(selector).MinOrDefault();
}
decimal? result = itemList.Where(x => x.Amount != 0).Min(x => (decimal?)x);
decimal result;
try{
  result = (from Item itm in itemList
                  where itm.Amount != 0
                  select (decimal?)itm.Amount).Min();
}catch(Exception e){
  result = 0;
}