C#using三种使⽤⽅式C#中托管与⾮托管C#托管资源和⾮托管资
源区别
1.using指令。using + 命名空间名字,这样可以在程序中直接⽤命令空间中的类型,⽽不必指定类型的详细命名空间,类似于Java的import,这个功能也是最常⽤的,⼏乎每个cs的程序都会⽤到。例如:using System; ⼀般都会出现在*.cs中。
2.using别名。using + 别名 = 包括详细命名空间信息的具体的类型。这种做法有个好处就是当同⼀个cs引⽤了两个不同的命名空间,但两个命名空间都包括了⼀个相同名字的类型的时候。当需要⽤到这个类型的时候,就每个地⽅都要⽤详细命名空间的办法来区分这些相同名字的类型。⽽⽤别名的⽅法会更简洁,⽤到哪个类就给哪个类做别名声明就可以了。注意:并不是说两个名字重复,给其中⼀个⽤了别名,另外⼀个就不需要⽤别名了,如果两个都要使⽤,则两个都需要⽤using来定义别名的。
1using System;
2
3using aClass = NameSpace1.MyClass;
4
5using bClass = NameSpace2.MyClass;
6
7
8
9namespace NameSpace1
10
11 {
12
13public class MyClass
14
15    {
16
17public override string ToString()
18
19        {
20
21return"You are in NameSpace1.MyClass";
22
23        }
24
25    }
26
27 }
28
29
30
31namespace NameSpace2
32
33 {
34
35class MyClass
36
37    {
38
39public override string ToString()
40
41        {
42
43return"You are in NameSpace2.MyClass";
44
45        }
46
47    }
48
49 }
50
51
52
53namespace testUsing
54
55 {
56
57using NameSpace1;
58
59using NameSpace2;
60
61///<summary>
62
63/// Class1 的摘要说明。
64
65///</summary>
66
67class Class1
68
70
71///<summary>
72
73///应⽤程序的主⼊⼝点。
74
75///</summary>
76
77        [STAThread]
78
79static void Main(string[] args)
80
81        {
82
83//
84
85// TODO: 在此处添加代码以启动应⽤程序
86
87//
88
89
90
91            aClass my1 = new aClass();
92
93            Console.WriteLine(my1);
94
95            bClass my2 = new bClass();
96
97            Console.WriteLine(my2);
98
99            Console.WriteLine("Press any key");
100
101            Console.Read();
102
103        }
104
105    }
106
107 }
3.using语句,定义⼀个范围,在范围结束时处理对象。
场景:
当在某个代码段中使⽤了类的实例,⽽希望⽆论因为什么原因,只要离开了这个代码段就⾃动调⽤这个类实例的Dispose。
要达到这样的⽬的,⽤atch来捕捉异常也是可以的,但⽤using也很⽅便。
1using (Class1 cls1 = new Class1(), cls2 = new Class1())
2
3 {
4
5// the code using cls1, cls2
6
7 } // call the Dispose on cls1 and cls2
  在 编程环境中,系统的资源分为托管资源和⾮托管资源。
  对于托管的资源的回收⼯作,是不需要⼈⼯⼲预回收的,⽽且你也⽆法⼲预他们的回收,所能够做的
只是了解 CLR如何做这些操作。也就是说对于您的应⽤程序创建的⼤多数对象,可以依靠 .NET
Framework 的垃圾回收器隐式地执⾏所有必要的内存管理任务。
  对于⾮托管资源,您在应⽤程序中使⽤完这些⾮托管资源之后,必须显⽰的释放他们,例如
System.IO.StreamReader的⼀个⽂件对象,必须显⽰的调⽤对象的Close()⽅法关闭它,否则会占⽤系统
的内存和资源,⽽且可能会出现意想不到的错误。
  我想说到这⾥,⼀定要清楚什么是托管资源,什么是⾮托管资源了?
  最常见的⼀类⾮托管资源就是包装操作系统资源的对象,例如⽂件,窗⼝或⽹络连接,对于这类资源
虽然垃圾回收器可以跟踪封装⾮托管资源的对象的⽣存期,但它不了解具体如何清理这些资源。还好
Framework提供了Finalize()⽅法,它允许在垃圾回收器回收该类资源时,适当的清理⾮托管资源。如果
在MSDN Library 中搜索Finalize将会发现很多类似的主题,这⾥列举⼏种常见的⾮托管资源:
ApplicationContext,Brush,Component,ComponentDesigner,Container,Context,Cursor,FileStream,Fon
t,Icon,Image,Matrix,Object,OdbcDataReader,OleDBDataReader,Pen,Regex,Socket,StreamWriter,Time
r,Tooltip 等等资源。可能在使⽤的时候很多都没有注意到!
关于托管资源,就不⽤说了撒,像简单的int,string,float,DateTime等等,中超过80%的资源都是托管资源。
⾮托管资源如何释放,.NET Framework 提供 Object.Finalize ⽅法,它允许对象在垃圾回收器回收该
对象使⽤的内存时适当清理其⾮托管资源。默认情况下,Finalize ⽅法不执⾏任何操作。如果您要让垃圾回收器在回收对象的内存之前对对象执⾏清理操作,您必须在类中重写 Finalize ⽅法。然⽽⼤家都可以发现在实际的编程中根本⽆法override⽅法Finalize(),在C#中,可以通过析构函数⾃动⽣成 Finalize ⽅法和对基类的 Finalize ⽅法的调⽤。
例如:
~MyClass()
{
  // Perform some cleanup operations here.
}   
该代码隐式翻译为下⾯的代码。
protected override void Finalize()
{
  try 
 // Perform some cleanup operations here. 
 }   
finally
  {   
  base.Finalize();
  }
}
但是,在编程中,并不建议进⾏override⽅法Finalize(),因为,实现 Finalize ⽅法或析构函数对性能
可能会有负⾯影响。⼀个简单的理由如下:⽤ Finalize ⽅法回收对象使⽤的内存需要⾄少两次垃圾回收
writeline翻译,
当垃圾回收器回收时,它只回收没有终结器(Finalize⽅法)的不可访问的内存,这时他不能回收具有终
结器(Finalize⽅法)的不可以访问的内存。它改为将这些对象的项从终⽌队列中移除并将他们放置在标记
为“准备终⽌”的对象列表中,该列表中的项指向托管堆中准备被调⽤其终⽌代码的对象,下次垃圾回收
器进⾏回收时,就回收并释放了这些内存。
托管的概念是在框架诞⽣后出现的。⽤⽐较通俗的话解释就是运⾏在框架下,并受框架管理的应⽤或其他组件称为托管的,反之为⾮托管的。
也就是说⽤平台开发出来的程序应该就是托管的了,⽽在以前开发的程序都属于⾮托管的。但是⾮托管的程序完全可以通过在平台下重新⽣成
⽽变成托管的,你就把 framework理解为⼀个Microsoft的Java Virtual Machine,这样,东西在上⾯跑,完全受控,这就是managed code。
在了解Finalize和Dispose之前,我们需要了解两个概念,⼀个是托管资源,⼀个⾮委托资源。
a.其中托管资源⼀般是指被CLR控制的内存资源,这些资源的管理可以由CLR来控制,例如程序中分配的对象,作⽤域内的变量等。
b.⽽⾮托管资源是CLR不能控制或者管理的部分,这些资源有很多,⽐如⽂件流,数据库的连接,系统的窗⼝句柄,打印机资源等等……这些资源⼀般情况下不存在于Heap(内存中⽤于存储对象实例的地⽅)中。 .Net平台中,CLR为程序员提供了⼀种很好的内存管理机制,使得程序员在编写代码时不需要显式的去释放⾃⼰使⽤的内存资源(这些在先前C和C++中是需要程序员⾃⼰去显式的释放的)。
这种管理机制称为GC(garbage collection)。GC的作⽤是很明显的,当系统内存资源匮乏时,它就会被激发,然后⾃动的去释放那些
没有被使⽤的托管资源(也就是程序员没有显式释放的对象)。但正如上⾯说的,CLR的GC功能也只能释放托管资源,对于⾮托管资源
例如窗⼝,⽂件和⽹络连接等,它都只能跟踪⾮托管资源的⽣存期,⽽不知道如何去释放它。这样就会出现当资源⽤尽时就不能提供资源
能够提供的服务,windows的运⾏速度就会变慢。这样的情况会出现在数据库的连接当中,当你没有显式的释放⼀个数据库资源时,
如果还是不断的申请数据库资源,那么到⼀定时候程序就会抛出⼀个异常。所以,当我们在类中封装了对⾮托管资源的操作时,我们就需
要显式,或者是隐式的释放这些资源。⽽上⾯提到的Finalize和Dispose⽅法分别就是隐式和显式操作中分别使⽤到的⽅法。
Finalize⼀般情况下⽤于基类不带close⽅法或者不带Dispose显式⽅法的类,也就是说,在Finalize过程中我们需要隐式的去实现⾮托管资源的释放,然后系统会在Finalize过程完成后,⾃⼰的去释放托管资源。如果要实现Dispose⽅法,可以通过实现IDisposable接⼝,
这样⽤户在使⽤这个类的同时就可以显⽰的执⾏Dispose⽅法,释放资源。
以下是MSDN上提出的Finalize和Dispose⽅法的使⽤指南,如果你的类遵循这个标准的话,你写出的类在.Net平台上就是⼀个“良民”。
Finalize 下⾯的规则概括了 Finalize ⽅法的使⽤指南。
1.仅在要求终结的对象上实现 Finalize。存在与 Finalize ⽅法相关的性能开销。如果需要 Finalize ⽅法,应考虑实现 IDisposable,
以使类的⽤户可以避免调⽤ Finalize ⽅法带来的开销。(juky_huang注:在实现IDisposable的类中,可以通过GC.SuppressFinalize来
停⽌Finalize的运⾏,这样只要显式的调⽤了Dispose⽅法,就能给⽤户提供更⼩的开销。如果⽤户没有显式的调⽤Dispose⽅法,也就是
没有停⽌Finalize的运⾏,这样就可以隐式的实现⾮托管资源的释放)
2.不要使 Finalize ⽅法更可见。它应该是 protected,⽽不是 public。 (juky_huang注:这个很重要,Finalize⽅法⼀般是系统调⽤,⽤户不去显式的调⽤它)
3.对象的 Finalize ⽅法应该释放对象拥有的任何外部资源。此外,Finalize ⽅法应该仅释放由对象控制的资源。Finalize ⽅法不应该引⽤任何其他对象。
4.不要对不是对象的基类的对象直接调⽤ Finalize ⽅法。在 C# 编程语⾔中,这不是有效的操作。
5.从对象的 Finalize ⽅法调⽤ base.Finalize ⽅法。(juky_huang注:就是派⽣类调⽤基类的Finalize⽅法) 注意基类的 Finalize ⽅法由 C#
和 C++ 的托管扩展的析构函数语法⾃动⽤。
Dispose 下⾯的规则概括了 Dispose ⽅法的使⽤指南:
1.在封装明确需要释放的资源的类型上实现处置设计⽅案。⽤户可以通过调⽤公共 Dispose ⽅法释放外部资源。
2.在通常包含控制资源的派⽣类型的基类型上实现处置设计⽅案,即使基类型并不需要。如果基类型有 close ⽅法,这通常指⽰需要实现Dispose。在这类情况下,不要在基类型上实现 Finalize ⽅法。应该在任何引⼊需要清理的资源的派⽣类型中实现 Finalize。
3.使⽤类型的 Dispose ⽅法释放类型所拥有的任何可处置资源。
4.对实例调⽤了 Dispose 后,禁⽌ Finalize ⽅法通过调⽤ GC.SuppressFinalize ⽅法运⾏。此规则的例外情况是当必须⽤ Finalize 完成Dispose 没有覆盖的⼯作时,但这种情况很少见。
5.如果基类实现 IDisposable,则调⽤基类的 Dispose ⽅法。
6.不要假定 Dispose 将被调⽤。如果 Dispose 未被调⽤,也应该使⽤ Finalize ⽅法释放类型所拥有的⾮托管资源。
7.处置了资源之后,在该类型(⾮ Dispose)上从实例⽅法引发⼀个 ObjectDisposedException。该规则不适⽤于 Dispose ⽅法,因为在不引发异常的情况下,该⽅法应该可以被多次调⽤。
8.通过基类型的层次结构将调⽤传播到 Dispose。Dispose ⽅法应释放此对象控制的所有资源和此对象所拥有的任何对象。例如,可以创建⼀个类似 TextReader 的对象来控制 Stream 和 Encoding,两者均在⽤户不知道的情况下由 TextReader 创建。另外,Stream 和 Encoding 都可以获取外部资源。当对 TextReader 调⽤Dispose⽅法时,它应该依次对 Stream 和 Encoding 调⽤ Dispose,使它们释放它们的外部资源。
9.应考虑在调⽤了对象的 Dispose ⽅法后不允许使⽤对象。重新创建已处置的对象是难以实现的⽅案。
10.允许 Dispose ⽅法被调⽤多次⽽不引发异常。此⽅法在⾸次调⽤后应该什么也不做。
有了以上的基础后,我们看⼀段代码,这段代码是Dispose的⼀个实现,这个代码如果仔细的去考虑的话,⾮常的有趣,在这⾥我们⼜会看到C#中⼀个⾮常常⽤的技术,多态性,如果你看过我在前⾯写的⼀篇关于虚拟⽅法的⽂章的话,你可以从中理解下⾯代码的精要之处。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。