Implicitly-Typed Variables in try…catch

2019-04-29 05:27发布

问题:

I like using implicit typing for almost everything because it's clean and simple. However, when I need to wrap a try...catch block around a single statement, I have to break the implicit typing in order to ensure the variable has a defined value. Here's a contrived hypothetical example:

var s = "abc";

// I want to avoid explicit typing here
IQueryable<ABC> result = null;
try {
    result = GetData();
} catch (Exception ex) { }

if (result != null)
    return result.Single().MyProperty;
else
    return 0;

Is there a way I can call GetData() with exception handling, but without having to explicitly define the type of the result variable? Something like GetData().NullOnException()?

回答1:

This is a common problem. I recommend that you just stick with your existing solution.

If you really want an alternative, here it is:

static T NullOnException<T>(Func<T> producer) where T : class {
  try { return producer(); } catch { return null; } //please modify the catch!
}

//now call it
var result = NullOnException(() => GetData());

Please modify this to log the exception or restrict the catch to a concrete type. I do not endorse swallowing all exceptions.

As this answer is being read a lot I want to point out that this implementation is just of demo-quality. In production code you probably should incorporate the suggestions given in the comments. Write yourself a robust, well-designed helper function that will serve you well for years.



回答2:

Just put your code inside the try:

var s = "abc";

// I want to avoid explicit typing here
try {
    var result = GetData();
    if (result != null)
        return result.Single().MyProperty;
    else
        return 0;
} catch (Exception ex) { }


回答3:

I came to a similar solution as @usr, but with slightly different semantics:

T LiftScope<T>(Func<T> ScopedFunction)
{
    T result = ScopedFunction();
    return result;
}

The purpose of LiftScope is to carry an internal variable out to the caller without compromising implicit typing. This could be used to solve the original problem, except that the try...catch would actually be embedded in the call.

try...catch

var result = 
    LiftScope(() => {
        try { return producer(); } catch { return null; }
    });

Now the caller is able to be responsible for exception handling. Furthermore, this can be used generically in a handful of similar use-cases where you have very short-lived scopes.

if

var result =
    LiftScope(() => {
        if (a == b)
            return GetData(true);
        else if (b == c)
            return GetData(false);
        else
            return GetData(true, 2);
    });

This could also be solved with a ternary-style if statement.

using

var result = 
    LiftScope(() => {
        using (var myContext = new MyDataContext())
        {
            return myContext.MyTable.Where(w => w.A == B).ToList();
        }
    });