C# 深化基本概念

关于IDisposable的Dispose方法

.Net中GC会自动回收托管资源, 对于非托管资源应该使用Dispose方法。 在使用Dispose方法时,应注意避免在Dispose内部中继续释放托管资源, 即防止Finalize方法被调用(   SuppressFinalize)。


结构不支持继承,可以实现接口。

 
结构不支持析构函数。 

析构函数既没有修饰符,也没有参数。

可以通过调用  Collect  强制进行垃圾回收,但大多数情况下应避免这样做,因为这样会导致性能问题。


不应使用空析构函数。 如果类包含析构函数,Finalize 队列中则会创建一个项。 调用析构函数时,将调用垃圾回收器来处理该队列。 如果析构函数为空,只会导致不必要的性能损失。

当应用程序封装窗口、文件和网络连接这类非托管资源时,应当使用析构函数释放这些资源。  当对象符合析构时,垃圾回收器将运行对象的 Finalize 方法。


使用 abstract 关键字可以创建必须在派生类中实现的不完整的类和类成员。

使用  sealed 关键字可以防止继承以前标记为  virtual 的类或某些类成员。


Finalize 

对象变为不可访问后将自动调用此方法,除非已通过 GC.SuppressFinalize 调用使对象免除了终结。在应用程序域的关闭期间,Finalize 将自动在没有免于终止的对象,甚至是那些仍可以访问的对象上调用。对于给定的实例仅自动调用 Finalize 一次,除非使用 GC.ReRegisterForFinalize 这类机制重新注册该对象并且后面没有调用GC.SuppressFinalize。

派生类型中的每个 Finalize 实现都必须调用其基类型的 Finalize 实现。这是唯一一种允许应用程序代码调用Finalize 的情况。

说明

因为 C# 编译器不允许直接执行 Finalize 方法,所以 C# 析构函数将自动调用基类的析构函数。

Finalize 操作具有下列限制:

  • 垃圾回收过程中执行终结器的准确时间是不确定的。不保证资源在任何特定的时间都能释放,除非调用Close 方法或 Dispose 方法。

  • 即使一个对象引用另一个对象,也不能保证两个对象的终结器以任何特定的顺序运行。即,如果对象 A 具有对对象 B 的引用,并且两者都有终结器,则当对象 A 的终结器启动时,对象 B 可能已经终结了。

  • 运行终结器的线程是未指定的。

在下面的异常情况下,Finalize 方法可能不会运行完成或可能根本不运行:

  • 另一个终结器无限期地阻止(进入无限循环,试图获取永远无法获取的锁,诸如此类)。由于运行时试图运行终结器来完成,所以如果一个终结器无限期地阻止,则可能不会调用其他终结器。

  • 进程终止,但不给运行时提供清理的机会。在这种情况下,运行时的第一个进程终止通知是 DLL_PROCESS_DETACH 通知。

在关闭过程中,只有当可终结对象的数目继续减少时,运行时才继续 Finalize 对象。

如果 Finalize 或 Finalize 的重写引发异常,并且运行时并非寄宿在重写默认策略的应用程序中,则运行时将终止进程,并且不执行任何活动的 try-finally 块或终结器。如果终结器无法释放或销毁资源,此行为可以确保进程完整性。


Finalize 会导致很大的性能损耗,如非必要,尽量不要使用。 Finalize只针对非托管资源进行清理,而不应该对托管资源实现Finalize。

MemberwiseClone 方法创建一个浅表副本,方法是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用同一对象。

例如,考虑引用对象 A 和 B 的被称为 X 的对象。对象 B 依次引用对象 C。X 的浅表副本创建一个新对象 X2,该对象也引用对象 A 和 B。相比而言,X 的深层副本创建一个新对象 X2,该对象引用新对象 A2 和 B2(分别为 A 和 B 的副本)。B2 又引用新对象 C2,C2 是 C 的副本。该示例阐释了浅层和深层复制操作之间的区别。

有很多方法可以实现深层复制操作,前提是浅表复制操作由 MemberwiseClone 方法执行但不符合您的需求。这些要求包括:

  • 调用要复制的对象的类构造函数以创建含有从第一个对象中提出的属性值的第二个对象。这假定对象的值完全由类构造函数定义。

  • 调用 MemberwiseClone 方法创建的对象的浅表副本,然后将指定新的对象,其值均相同,原始对象的任何属性或字段的值是引用类型。该示例中的 DeepCopy 方法阐释了这种方法。

  • 序列化要深层复制的对象,然后将序列化的数据还原到另一个对象变量。

  • 使用带递归的反射执行的深层复制操作。



关于垃圾回收器;

系统会默认调用类的析构函数, 而类的析构函数会默认调用Finalize,调用此方法后


using 

using语句确保继承自IDisposable的对象的Dispose方法被正确调用。当using语句内对象超出范围时,不管有没有异常出现,都会被调用它的Dispose方法。

例如:

using (Font font1 = new Font("Arial", 10.0f))  {     byte charset = font1.GdiCharSet; } 

 实际转化代码为: 

 {   Font font1 = new Font("Arial", 10.0f);   try   {     byte charset = font1.GdiCharSet;   }   finally   {     if (font1 != null)       ((IDisposable)font1).Dispose();   } } 


readonly与const


readonly 关键字与 const 关键字不同。  const 字段只能在该字段的声明中初始化。  readonly 字段可以在声明或构造函数中初始化。  因此,根据所使用的构造函数,readonly 字段可能具有不同的值。  另外,const字段为编译时常数,而 readonly 字段可用于运行时常数,如下例所示:

隐士类型的局部变量


var只能申明局部变量,仅在需要时使用var。不能赋值为null,数组和匿名函数。

Linq



所有linq查询操作都是由3部分组成:获取数据源、创建查询、执行查询。

LINQ 数据源(可查询数据源)是支持泛型  IEnumerable<T>  接口或从该接口继承的接口的任意对象。可查询数据源就是不需要修改或者特殊处理就可以用作Linq的数据源。

linq的查询语句和sql语句的顺序相反, 比如下面的from,where,select
from cust in db.Customers     where cust.City == "London"     select cust; 
 
查询变量只是存储查询命令, 实际的查询执行可能延迟到foreach、Count、Max、Average、First等。 (延迟执行)

利用linq查询Array时,需要主动声明变量类型, 比如:
from Custom cust in db.Customers


查询操作符:


对数据进行排序 (OrderBy,ThenBy,OrderByDescending)

Set 运算 (Distinct,Except,Intersect,Union)

筛选数据 (OfType,Where)

限定符操作 (All,Any,Contains)

投影运算 (Select,SelectMany)

数据分区 (Skip,SkipWhile,Take,TakeWhile)

联接运算 (Join, GroupJoin)

数据分组 (GroupBy, ToLookup)

串联运算 (Concat)



Linq中立即执行与延迟执行的操作符/方法:

标准查询运算符

Return Type

立即执行

延迟流式执行

延迟非流式执行

Aggregate

TSource

X

 

 

All<TSource>

Boolean

X

 

 

Any

Boolean

X

 

 

AsEnumerable<TSource>

IEnumerable<T>

 

X

 

Average

单个数值

X

 

 

Cast<TResult>

IEnumerable<T>

 

X

 

Concat<TSource>

IEnumerable<T>

 

X

 

Contains

Boolean

X

 

 

Count

Int32

X

 

 

DefaultIfEmpty

IEnumerable<T>

 

X

 

Distinct

IEnumerable<T>

 

X

 

ElementAt<TSource>

TSource

X

 

 

ElementAtOrDefault<TSource>

TSource

X

 

 

Empty<TResult>

IEnumerable<T>

X

 

 

Except

IEnumerable<T>

 

X

 X

First

TSource

X

 

 

FirstOrDefault

TSource

X

 

 

GroupBy

IEnumerable<T>

 

 

X

GroupJoin

IEnumerable<T>

 

X

Intersect

IEnumerable<T>

 

X

X

Join

IEnumerable<T>

 

X

X

Last

TSource

X

 

 

LastOrDefault

TSource

X

 

 

LongCount

Int64

X

 

 

Max

单个数值、TSource 或 TResult

X

 

 

Min

单个数值、TSource 或 TResult

X

 

 

OfType<TResult>

IEnumerable<T>

 

X

 

OrderBy

IOrderedEnumerable<TElement>

 

 

X

OrderByDescending

IOrderedEnumerable<TElement>

 

 

X

Range

IEnumerable<T>

 

X

 

Repeat<TResult>

IEnumerable<T>

 

X

 

Reverse<TSource>

IEnumerable<T>

 

 

X

Select

IEnumerable<T>

 

X

 

SelectMany

IEnumerable<T>

 

X

 

SequenceEqual

Boolean

X

 

 

Single

TSource

X

 

 

SingleOrDefault

TSource

X

 

 

Skip<TSource>

IEnumerable<T>

 

X

 

SkipWhile

IEnumerable<T>

 

X

 

Sum

单个数值

X

 

 

Take<TSource>

IEnumerable<T>

 

X

 

TakeWhile

IEnumerable<T>

 

X

 

ThenBy

IOrderedEnumerable<TElement>

 

 

X

ThenByDescending

IOrderedEnumerable<TElement>

 

 

X

ToArray<TSource>

TSource 数组

X

 

 

ToDictionary

Dictionary<TKey, TValue>

X

 

 

ToList<TSource>

IList<T>

X

 

 

ToLookup

ILookup<TKey, TElement>

X

 

 

Union

IEnumerable<T>

 

X

 

Where

IEnumerable<T>

 

X

 




MarshalByRefObject 类


MarshalByRefObject类支持跨应用程序域传递对象, 或者远程传递对象。

例如:

using System; using System.Reflection;  public class Worker : MarshalByRefObject {     public void PrintDomain()      {          Console.WriteLine("Object is executing in AppDomain \"{0}\"",             AppDomain.CurrentDomain.FriendlyName);      } }  class Example {     public static void Main()     {         // Create an ordinary instance in the current AppDomain         Worker localWorker = new Worker();         localWorker.PrintDomain();          // Create a new application domain, create an instance         // of Worker in the application domain, and execute code         // there.         AppDomain ad = AppDomain.CreateDomain("New domain");         Worker remoteWorker = (Worker) ad.CreateInstanceAndUnwrap(             Assembly.GetExecutingAssembly().FullName,             "Worker");         remoteWorker.PrintDomain();     } }  /* This code produces output similar to the following:  Object is executing in AppDomain "source.exe" Object is executing in AppDomain "New domain"  */

//例2
using System; using System.Runtime.Remoting; using System.Security.Permissions;  public class SetObjectUriForMarshalTest  {      class TestClass : MarshalByRefObject {     }      [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)]      public static void Main()  {          TestClass obj = new TestClass();              RemotingServices.SetObjectUriForMarshal(obj, "testUri");         RemotingServices.Marshal(obj);          Console.WriteLine(RemotingServices.GetObjectUri(obj));     } } 




你可能感兴趣的:(开发技术)