使用 abstract 关键字可以创建必须在派生类中实现的不完整的类和类成员。
对象变为不可访问后将自动调用此方法,除非已通过 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 块或终结器。如果终结器无法释放或销毁资源,此行为可以确保进程完整性。
MemberwiseClone 方法创建一个浅表副本,方法是创建一个新对象,然后将当前对象的非静态字段复制到该新对象。如果字段是值类型的,则对该字段执行逐位复制。如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用同一对象。
例如,考虑引用对象 A 和 B 的被称为 X 的对象。对象 B 依次引用对象 C。X 的浅表副本创建一个新对象 X2,该对象也引用对象 A 和 B。相比而言,X 的深层副本创建一个新对象 X2,该对象引用新对象 A2 和 B2(分别为 A 和 B 的副本)。B2 又引用新对象 C2,C2 是 C 的副本。该示例阐释了浅层和深层复制操作之间的区别。
有很多方法可以实现深层复制操作,前提是浅表复制操作由 MemberwiseClone 方法执行但不符合您的需求。这些要求包括:
调用要复制的对象的类构造函数以创建含有从第一个对象中提出的属性值的第二个对象。这假定对象的值完全由类构造函数定义。
调用 MemberwiseClone 方法创建的对象的浅表副本,然后将指定新的对象,其值均相同,原始对象的任何属性或字段的值是引用类型。该示例中的 DeepCopy 方法阐释了这种方法。
序列化要深层复制的对象,然后将序列化的数据还原到另一个对象变量。
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(); } }
from cust in db.Customers where cust.City == "London" select cust;
标准查询运算符 |
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 |
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 |
|
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" */
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)); } }