如果找到多个实例则返回null



我有一个IEnumerable和一个谓词(Func),我正在编写一个方法,如果列表中只有一个实例与谓词匹配,则返回一个值。如果没有匹配条件,则没有找到任何条件。如果条件与许多实例相匹配,则谓词不足以成功标识所需的记录。这两种情况都应该返回null。

在LINQ中不导致列表的多个枚举的推荐表达方式是什么?

如果找到多个实例,LINQ操作符SingleOrDefault将抛出异常。LINQ操作符FirstOrDefault将返回第一个,即使找到多个。

MyList.Where(predicate).Skip(1).Any() 

…将检查歧义,但不保留所需的记录。

似乎我最好的举动是从MyList.Where(谓词)中抓取Enumerator并保留第一个实例,如果访问下一个项目失败,但它似乎有点冗长。

我错过了什么明显的吗?

"稍微冗长"选项对我来说似乎是合理的,并且可以很容易地分离成单个扩展方法:

// TODO: Come up with a better name :)
public static T SingleOrDefaultOnMultiple<T>(this IEnumerable<T> source)
{
    // TODO: Validate source is non-null
    using (var iterator = source.GetEnumerator())
    {
        if (!iterator.MoveNext())
        {
            return default(T);
        }
        T first = iterator.Current;
        return iterator.MoveNext() ? default(T) : first;
    }
}

Update:这是一种更通用的方法,可能更易于重用。

public static IEnumerable<TSource> TakeIfCountBetween<TSource>(this IEnumerable<TSource> source, int minCount, int maxCount, int? maxTake = null)
{
    if (source == null)
            throw new ArgumentNullException("source");
    if (minCount <= 0 || minCount > maxCount)
        throw new ArgumentException("minCount must be greater 0 and less than or equal maxCount", "minCount");
    if (maxCount <= 0)
        throw new ArgumentException("maxCount must be greater 0", "maxCount");
    int take = maxTake ?? maxCount;
    if (take > maxCount)
        throw new ArgumentException("maxTake must be lower or equal maxCount", "maxTake");
    if (take < minCount)
        throw new ArgumentException("maxTake must be greater or equal minCount", "maxTake");
    int count = 0;
    ICollection objCol;
    ICollection<TSource> genCol = source as ICollection<TSource>;
    if (genCol != null)
    {
        count = genCol.Count;
    }
    else if ((objCol = source as ICollection) != null)
    {
        count = objCol.Count;
    }
    else
    {
        using (IEnumerator<TSource> enumerator = source.GetEnumerator())
        {
            while (enumerator.MoveNext() && ++count < maxCount);
        }
    }
    bool valid = count >= minCount && count <= maxCount;
    if (valid)
        return source.Take(take);
    else
        return Enumerable.Empty<TSource>();
}

用法:

var list = new List<string> { "A", "B", "C", "E", "E", "F" };
IEnumerable<string> result = list
    .Where(s => s == "A")
    .TakeIfCountBetween(1, 1);
Console.Write(string.Join(",", result)); // or result.First()

相关内容

  • 没有找到相关文章

最新更新