0

我正在尝试使用 SelectMany 编译列表列表,但是选择器可能会遇到错误,因此没有结果。

我将提供我正在尝试编写的实际功能,然后提供我编写的代码片段以进一步探索它。

在生产代码中,我的目标是处理序列化程序抛出异常的情况。

在示例代码中,我已经解决了字符串情况下的问题,但我不确定这个解决方案是否真的不仅仅是一个 hack。

生产代码:

public List<click> Clicks(int advertiserId, DateTime date)
{
    var dirInfo = new DirectoryInfo(DirName(date, advertiserId));
    if (dirInfo.Exists)
    {
        var files = dirInfo.EnumerateFiles();
        var clicks = files.SelectMany(c =>
            {
                using (var stream = c.OpenRead())
                {
                    return (click[])clicksSerializer.Deserialize(stream);
                }              
            });
        return clicks.ToList();
    }
    return null;
}

示例代码:

void Main()
{
    var ids = new [] { 1, 2, 3 };
    var names = ids.SelectMany(id =>
        {
            try
            {
                return GetNames(id);
            }
            catch
            {
                Console.WriteLine ("Error getting names for {0}", id);

                // RESULT: NullReferenceException at System.Linq.Enumerable.<SelectManyIterator>d__14`2.MoveNext()
                //return null;

                // RESULT: an empty string in the result, but how to this with other types?
                return new string [] { string.Empty };
            }
        });
    foreach (var name in names)
    {
        Console.WriteLine ("Name: {0}", name);
    }
}

string[] GetNames(int id)
{
    switch (id)
    {
        case 1:
            return new [] {"Jim", "Bob"};
        case 2:
            return new [] {"Harry", "Larry"};
        default:
            throw new Exception("invalid id");
    }
} 
4

2 回答 2

3

是的,返回一个空序列是完全有效的,虽然我会使用

return Enumerable.Empty<string>();

而是更清楚。

SelectMany- 以您使用的形式 - 确实只是将序列序列展平,如果其中一些中间序列是空的,它们只会对整个序列没有任何贡献。完全没有问题。

于 2013-06-20T21:41:54.833 回答
1

您可以返回default(T)其他类型,T尽管我不确定这会有多大用处:

public static IEnumerable<T> TrySelectMany<T>(this IEnumerable<T> seq, Func<T, IEnumerable<T>> selector)
{
    return seq.SelectMany(i => {
        try {
            return selector(i);
        }
        catch(Exception) {
            return new T[] { default(T) };
        }
    });
}

我会考虑Enumerable.Empty<T>()在 catch 块中返回。

于 2013-06-20T21:45:22.830 回答