【问题标题】:Implicitly-Typed Variables in try...catchtry...catch 中的隐式类型变量
【发布时间】:2012-12-13 22:23:11
【问题描述】:

我喜欢对几乎所有内容都使用隐式类型,因为它简洁明了。但是,当我需要在单个语句周围包装 try...catch 块时,我必须打破隐式类型以确保变量具有定义的值。这是一个人为的假设示例:

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;

有没有一种方法可以调用GetData() 进行异常处理,但不必显式定义结果变量的类型? GetData().NullOnException() 之类的东西?

【问题讨论】:

  • 你的意思是要添加扩展方法?
  • @tia:我只是想这可能是实现它的一种方式。理想情况下,我希望能够在处理异常时说 var result = GetData()
  • 一个“愚蠢”的解决方案是在同一个地方声明 result,在 try 之前,就像这样:var result = (IQueryable&lt;ABC&gt;)null; 但是这比你输入的更多有。只有当局部变量没有被分配到声明它的同一行时,才绝对不可能使用var

标签: c# .net try-catch implicit-typing


【解决方案1】:

我找到了与@usr 类似的解决方案,但语义略有不同:

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

LiftScope 的目的是在不影响隐式类型的情况下将内部变量传递给调用者。这可以用来解决最初的问题,只是 try...catch 实际上会嵌入到调用中。

try...catch

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

现在调用者可以负责异常处理。此外,这可以通用地用于少数类似的使用案例,其中您的作用域非常短暂。

if

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

这也可以通过三元样式的if 语句来解决。

using

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

【讨论】:

    【解决方案2】:

    这是一个常见问题。我建议您坚持使用现有的解决方案。

    如果你真的想要一个替代方案,这里是:

    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());
    

    请修改它以记录异常或将捕获限制为具体类型。我不赞成吞下所有的例外。

    由于这个答案被大量阅读,我想指出这个实现只是演示质量。在生产代码中,您可能应该结合 cmets 中给出的建议。为自己编写一个健壮的、精心设计的辅助函数,它将为您服务多年。

    【讨论】:

    • +1 这就是我的想法,但不太确定该怎么做。
    • 也许添加第二个Action&lt;Exception&gt; 来处理异常。我假设 catch 块在这里只是空的,因为它不会影响问题,而不是因为那里真的什么都没有。
    • @Servy 我完全同意。我没有花时间充实这个示例代码。在我的生产代码中,我的结果类型通常为Tuple&lt;T, Exception&gt;
    • @usr 是的,如果你有一个Action&lt;Exception&gt;,如果你还需要把它放到更高的范围内,你总是可以把它放到一个封闭的本地。我猜这主要是个人喜好。
    • 哦,你可以返回default(T)(或者有一个默认的可选参数)而不是null,这样你就不需要class的限制了。
    【解决方案3】:

    只需将您的代码放入 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) { }
    

    【讨论】:

    • 我做的例子确实让它有点太简单了:) 假设还有另外 30 行代码,我真的不想把它全部包装在 try...catch 中。
    • @mellamokb 那你不在范围内,不能使用var?也许你需要想出一个更好的例子或其他东西。
    • 您可以将“额外”代码提取到一个单独的函数中,但如果它在逻辑上属于该函数,我觉得这永远不会正确。
    • 顺便说一句,我个人认为使用隐式类型可以快速编写你不记得类型是什么,或者你不确定等的代码......但我总是转换回显式类型。 (我使用 Ctrl-` 但我不记得这是内置的还是附加组件。)
    • @mellamokb: 嗯,我想可能是 CodeRush Xpress 版本或什么的......当我使用该命令时,它给了我一个红色的半透明大箭头,指向新的显式类型名称并说“制作显式”,所以它绝对不是内置的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-26
    • 2015-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多