从 using() 语句中返回是否会有任何副作用?

126

在使用语句中从内部返回一个方法值,获取DataContext似乎总是可以很好地工作,就像这样:

public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        var transaction = (from t in db.Transactions
                              orderby t.WhenCreated descending
                              where t.Id == singleId
                              select t).SingleOrDefault();
        return transaction;
    }
}

但我总觉得在跳出using括号之前,应该先完成某些操作,例如在using语句之前定义事务,然后在括号内获取其值,在括号之后返回。

将变量的定义和返回放在using括号外面是否是更好的做法,或者能以某种方式节省资源?


1
可能看一下这个变体的通用IL会很有趣。我怀疑生成的IL没有太大的区别。我通常甚至不会声明var transaction - 只需返回表达式的结果即可。 - Jonesie
5个回答

166
不,我认为这样更清晰。不用担心,“Dispose”仍然会在“退出时”被调用,而且只有在返回值完全计算后才会被调用。如果在任何时候抛出异常(包括计算返回值时),“Dispose”仍将被调用。
虽然你肯定可以采用更冗长的路线,但这只是增加了混乱和额外的上下文(在脑海中跟踪)。实际上,你并不真正需要额外的局部变量 - 虽然在调试方面可能很方便。你可以只写:
public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        return (from t in db.Transactions
                orderby t.WhenCreated descending
                where t.Id == singleId
                select t).SingleOrDefault();
    }
}

实际上,我甚至可能会倾向于使用点符号表示法,并将 Where 条件放在 SingleOrDefault 内:

public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        return db.Transactions.OrderByDescending(t => t.WhenCreated)
                              .SingleOrDefault(t => t.Id == singleId);
    }
}

2
既然是你@jon,如果在using块内抛出异常,是否仍然安全? - Dave Archer
7
是的,使用关键字“using”只是对try/finally结构的一种简化语法糖。 - Mitch Wheat
2
为什么要将 OrderByDescending 与 SingleOrDefault 结合使用? - erikkallen
2
@erikkallen:不幸的是,LINQ没有“MaxBy”函数,因此您无法获取具有最大值的行。对于LINQ到对象,您可以很容易地编写自己的函数,但我不确定在这种情况下有更好的方法。您会建议使用什么替代方案? - Jon Skeet
@Menol:using语句怎么会做到这一点呢?恐怕我不理解你的观点。 (这里没有任何东西被最终确定...它正在被处理。那不是同一件事情。) - Jon Skeet
显示剩余5条评论

33

请看这个

理解C#中的'using'语句

CLR将您的代码转换为MSIL。 'using'语句会被转换成一个try和finally块,这就是'using'语句在IL中的表示方式。'using'语句被分为三个部分:获取、使用和处理。首先获取资源,然后使用该资源并将其放在try语句中,最后在finally子句中处理对象。


4
一个有趣的见解。谢谢。 - Kangkan
1
这将翻译成以下问题:从 try-finally 的 try 块返回是否有任何副作用? - H H
3
不,finally块将始终被调用。http://www.techinterviews.com/interview-questions-for-c-developers - Adriaan Stander

6

使用using()语句返回后没有任何副作用。

它是否使代码更易读是另一个讨论话题。


0

我认为,都一样。代码没有问题。.NET框架不关心对象是在哪里创建的。重要的是它是否被引用。


-1

是的,可能会有副作用。例如,如果您在 ASP.NET MVC 动作方法中使用相同的技术,您将收到以下错误消息:“ObjectContext 实例已被处理并且不能再用于需要连接的操作。”

public ActionResult GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        var transaction = (from t in db.Transactions
                              orderby t.WhenCreated descending
                              where t.Id == singleId
                              select t).SingleOrDefault();
        return PartialView("_transactionPartial", transaction);
    }
}

2
如果你在using语句之外定义事务,你将会得到相同的错误。在这种情况下,using关键字是无关的。 - Costa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接