Answers:
的原因 using
语句是要确保对象在超出范围后立即被处置,并且不需要显式代码即可确保这种情况发生。
与理解C#(codeproject)中的'using'语句和使用实现IDisposable的对象(microsoft)中一样,C#编译器将转换
using (MyResource myRes = new MyResource())
{
myRes.DoSomething();
}
至
{ // Limits scope of myRes
MyResource myRes= new MyResource();
try
{
myRes.DoSomething();
}
finally
{
// Check for a null resource.
if (myRes != null)
// Call the object's Dispose method.
((IDisposable)myRes).Dispose();
}
}
C#8引入了一种新语法,名为“ using Declarations ”:
using声明是在using关键字之后的变量声明。它告诉编译器应将声明的变量放在封闭范围的末尾。
因此,上述等效代码为:
using var myRes = new MyResource();
myRes.DoSomething();
当控件离开包含范围(通常是一种方法,但也可以是代码块)时,myRes
将被处置。
using
确保Dispose
在处理完对象后立即调用该方法。
MyRessource
是struct 时,生成的代码有些不同。很明显,没有针对无效性的测试,也没有对的装箱IDisposable
。发出了受限的虚拟呼叫。
using
,则内置在其中的变量为只读。如果没有该using
语句,就无法对局部变量实现此目的。
由于仍有很多人这样做:
using (System.IO.StreamReader r = new System.IO.StreamReader(""))
using (System.IO.StreamReader r2 = new System.IO.StreamReader("")) {
//code
}
我想很多人仍然不知道您可以做到:
using (System.IO.StreamReader r = new System.IO.StreamReader(""), r2 = new System.IO.StreamReader("")) {
//code
}
像这样的事情:
using (var conn = new SqlConnection("connection string"))
{
conn.Open();
// Execute SQL statement here on the connection you created
}
这SqlConnection
将被关闭,而无需显式调用该.Close()
函数,并且即使抛出异常也将发生这种情况,而无需使用try
/ catch
/ finally
。
return
位于using
块中间,连接仍将关闭。
在某种意义上使用
using (var foo = new Bar())
{
Baz();
}
实际上是try / finally块的简写。它等效于代码:
var foo = new Bar();
try
{
Baz();
}
finally
{
foo.Dispose();
}
您当然会注意到,第一个代码段比第二个代码段要简洁得多,而且即使抛出异常,您也可能想做许多事情来进行清理。因此,我们提出了一个称为Scope的类,该类使您可以在Dispose方法中执行任意代码。因此,例如,如果您有一个名为IsWorking的属性,在尝试执行某个操作后始终希望将其设置为false,则可以这样做:
using (new Scope(() => IsWorking = false))
{
IsWorking = true;
MundaneYetDangerousWork();
}
Microsoft文档指出,使用具有双重功能(https://msdn.microsoft.com/zh-cn/library/zhdeatwt.aspx),既可以用作指令也可以用作in 语句。作为声明,正如在其他答案中在此指出的那样,该关键字基本上是语法糖,用于确定处置IDisposable对象的范围。作为指令,它通常用于导入名称空间和类型。同样,作为指令,您可以创建约瑟夫(Joseph)和本·阿尔巴哈里(Ben Albahari)的别名(为名称空间和类型,如《 C#5.0简而言之:权威指南》(http://www.amazon.com/5-0-Nutshell-The-权威参考书/ dp / B008E6I1K8)。一个例子:
namespace HelloWorld
{
using AppFunc = Func<IDictionary<DateTime, string>, List<string>>;
public class Startup
{
public static AppFunc OrderEvents()
{
AppFunc appFunc = (IDictionary<DateTime, string> events) =>
{
if ((events != null) && (events.Count > 0))
{
List<string> result = events.OrderBy(ev => ev.Key)
.Select(ev => ev.Value)
.ToList();
return result;
}
throw new ArgumentException("Event dictionary is null or empty.");
};
return appFunc;
}
}
}
这是明智的选择,因为滥用这种做法会损害代码的清晰度。在DotNetPearls(http://www.dotnetperls.com/using-alias)中,有一个关于C#别名的很好的解释,也提到了利弊。
using
用作别名工具。当阅读代码时,这使我感到困惑-我已经知道System.Collections
存在并且具有IEnumerable<T>
该类。使用别名对其进行其他处理会使我感到困惑。我认为using FooCollection = IEnumerable<Foo>
这是使以后的开发人员阅读代码并思考的一种方式,“到底是什么FooCollection
,为什么在某个地方没有它的类?” 我从不使用它,并且会阻止它的使用。但这可能只是我。
过去,我已经使用很多它来处理输入和输出流。您可以很好地嵌套它们,这样可以消除通常遇到的许多潜在问题(通过自动调用dispose)。例如:
using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
{
using (BufferedStream bs = new BufferedStream(fs))
{
using (System.IO.StreamReader sr = new StreamReader(bs))
{
string output = sr.ReadToEnd();
}
}
}
using的另一个重要用途是在实例化模式对话框时。
Using frm as new Form1
Form1.ShowDialog
' do stuff here
End Using
总之,当您使用实现的类型的局部变量时IDisposable
,始终无一例外地使用using
1。
如果您使用非局部IDisposable
变量,那么请始终实现IDisposable
pattern。
两个简单的规则,也不例外1。否则,防止资源泄漏是* ss的真正痛苦。
1):唯一的例外是–处理例外时。这样,Dispose
在该finally
块中显式调用的代码可能会更少。
您可以通过以下示例使用别名名称空间:
using LegacyEntities = CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects;
如您所见,这被称为using别名指令,如果您想在代码中使其变得显而易见,则可以将其用于隐藏长引用,例如
LegacyEntities.Account
代替
CompanyFoo.CoreLib.x86.VBComponents.CompanyObjects.Account
或简单地
Account // It is not obvious this is a legacy entity
有趣的是,您还可以将using / IDisposable模式用于其他有趣的事情(例如Rhino Mocks使用它的另一点)。基本上,您可以利用编译器将始终在“ used”对象上调用.Dispose 的事实。如果您需要在某个操作之后发生某些事情……有一个明确的开始和结束……那么您可以简单地创建一个IDisposable类,该类在构造函数中启动操作,然后在Dispose方法中完成。
这使您可以使用非常好的using语法来表示所述操作的显式开始和结束。这也是System.Transactions东西的工作方式。
“使用”还可以用于解决名称空间冲突。请参阅http://www.davidarno.org/c-howtos/aliases-overcoming-name-conflicts/,以获取我撰写的简短教程。
public class ClassA:IDisposable
{
#region IDisposable Members
public void Dispose()
{
GC.SuppressFinalize(this);
}
#endregion
}
public void fn_Data()
{
using (ClassA ObjectName = new ClassA())
{
//use objectName
}
}
using关键字定义对象的作用域,然后在作用域完成后处置该对象。例如。
using (Font font2 = new Font("Arial", 10.0f))
{
// use font2
}
有关C#using关键字的MSDN文章,请参见此处。
并不是说它非常重要,但是使用还可用于即时更改资源。是的,就像前面提到的那样,是一次性的,但是也许您在执行的其余部分中不希望它们与其他资源不匹配。因此,您希望对其进行处理,以免其他地方受到干扰。
感谢下面的评论,我将对此文章进行一些整理(我不应该在那时使用“垃圾收集”一词道歉):
当您使用using时,它将在对象上调用Dispose()方法在使用范围的末尾。因此,您的Dispose()方法中可以包含很多很棒的清理代码。
这里有一个要点,希望它可能不会引起关注:如果实现IDisposable,请确保在Dispose()实现中调用GC.SuppressFinalize(),否则自动垃圾收集将尝试并在某些情况下完成该过程要点,如果您已经对此进行了Dispose()d,至少会浪费资源。
将对象立即丢弃的合理使用的另一个示例:
using (IDataReader myReader = DataFunctions.ExecuteReader(CommandType.Text, sql.ToString(), dp.Parameters, myConnectionString))
{
while (myReader.Read())
{
MyObject theObject = new MyObject();
theObject.PublicProperty = myReader.GetString(0);
myCollection.Add(theObject);
}
}
它也可以用于创建示例的范围:
class LoggerScope:IDisposable {
static ThreadLocal<LoggerScope> threadScope =
new ThreadLocal<LoggerScope>();
private LoggerScope previous;
public static LoggerScope Current=> threadScope.Value;
public bool WithTime{get;}
public LoggerScope(bool withTime){
previous = threadScope.Value;
threadScope.Value = this;
WithTime=withTime;
}
public void Dispose(){
threadScope.Value = previous;
}
}
class Program {
public static void Main(params string[] args){
new Program().Run();
}
public void Run(){
log("something happend!");
using(new LoggerScope(false)){
log("the quick brown fox jumps over the lazy dog!");
using(new LoggerScope(true)){
log("nested scope!");
}
}
}
void log(string message){
if(LoggerScope.Current!=null){
Console.WriteLine(message);
if(LoggerScope.Current.WithTime){
Console.WriteLine(DateTime.Now);
}
}
}
}
using
C#中关键字的两种用法如下。
作为指示
通常,我们使用using
关键字在代码隐藏文件和类文件中添加名称空间。然后,它使当前页面中的所有类,接口和抽象类以及它们的方法和属性可用。
例:
using System.IO;
作为声明
这是using
在C#中使用关键字的另一种方法。它在提高垃圾收集性能方面起着至关重要的作用。
该using
语句确保即使在创建对象以及调用方法,属性等时发生异常,也将调用Dispose()。Dispose()是IDisposable接口中提供的一种方法,可帮助实现自定义垃圾收集。换句话说,如果我正在执行某些数据库操作(“插入”,“更新”,“删除”),但由于某种原因发生了异常,则在此using语句会自动关闭连接。无需显式调用连接Close()方法。
另一个重要因素是它有助于连接池。.NET中的连接池有助于避免多次关闭数据库连接。它将连接对象发送到池中以备将来使用(下一次数据库调用)。下次从应用程序中调用数据库连接时,连接池将获取池中可用的对象。因此,它有助于提高应用程序的性能。因此,当我们使用using语句时,控制器自动将对象发送到连接池,无需显式调用Close()和Dispose()方法。
您可以通过使用try-catch块并在finally块内显式调用Dispose()来执行与using语句相同的操作。但是using语句会自动执行调用,以使代码更整洁和美观。在using块中,该对象是只读的,无法修改或重新分配。
例:
string connString = "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;";
using (SqlConnection conn = new SqlConnection(connString))
{
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "SELECT CustomerId, CompanyName FROM Customers";
conn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
Console.WriteLine("{0}\t{1}", dr.GetString(0), dr.GetString(1));
}
}
在前面的代码中,我没有关闭任何连接;它将自动关闭。该using
语句将自动调用conn.Close(),因为该using
语句(using (SqlConnection conn = new SqlConnection(connString)
)与SqlDataReader对象的相同。并且,如果发生任何异常,它将自动关闭连接。
有关更多信息,请参见C#中的用法和重要性。
使用子句用于定义特定变量的范围。例如:
Using(SqlConnection conn=new SqlConnection(ConnectionString)
{
Conn.Open()
// Execute sql statements here.
// You do not have to close the connection explicitly here as "USING" will close the connection once the object Conn becomes out of the defined scope.
}