Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
545 views
in Technique[技术] by (71.8m points)

c# - LINQ query to perform a projection, skipping or wrapping exceptions where source throws on IEnumerable.GetNext()

I'd like a general solution but as an example, assume i have an IEnumerable<string>, where some can be parsed as integers, and some cannot.

var strings = new string[] { "1", "2", "notint", "3" };

Obviously if i did Select(s => int.Parse(s, temp)) it'd throw an exception when enumerated.

In this case i could do .All(s => int.TryParse(s, out temp)) first, however i want a general solution where i don't have to enumerate the IEnumerable twice.

Ideally i'd like to be able to do the following, which calls my magic exception skipping method:

// e.g. parsing strings
var strings = new string[] { "1", "2", "notint", "3" };
var numbers = strings.Select(s => int.Parse(s)).SkipExceptions();
// e.g. encountering null object
var objects = new object[] { new object(), new object(), null, new object() }
var objecttostrings = objects.Select(o => o.ToString()).SkipExceptions();
// e.g. calling a method that could throw
var myClassInstances = new MyClass[] { new MyClass(), new MyClass(CauseMethodToThrow:true) };
var myClassResultOfMethod = myClassInstances.Select(mci => mci.MethodThatCouldThrow()).SkipExceptions();

How can i write the SkipExceptions() extension method?


Some great answers for a SelectSkipExceptions() method, however i wonder if a SkipExceptions() method could be created, along the same lines as AsParallel().

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

How about this (you might want to give this special Select Extension a better name)

public static IEnumerable<TOutput> SelectIgnoringExceptions<TInput, TOutput>(
    this IEnumerable<TInput> values, Func<TInput, TOutput> selector)
   {
        foreach (var item in values)
        {
            TOutput output = default(TOutput);

            try
            {
                output = selector(item);
            }
            catch 
            {
                continue;
            }

            yield return output;
        }
    }

Edit5 Added a using statement, thanks for the suggestion in comments

    public static IEnumerable<T> SkipExceptions<T>(
        this IEnumerable<T> values)
    {
        using(var enumerator = values.GetEnumerator())
        {
           bool next = true;
           while (next)
           {
               try
               {
                   next = enumerator.MoveNext();
               }
               catch
               {
                   continue;
               }

               if(next) yield return enumerator.Current;
           } 
        }
    }

However this relies on the incoming IEnumerable not already being created (and therefore already having thrown Exceptions) as a list by the preceding Function. E.g. this would probably not work if you call it like this: Select(..).ToList().SkipExceptions()


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...