SUMTEC -- There's a thing in my bloglet.

But it's not only one. It's many. It's the same as other things but it exactly likes nothing else...

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

大家都知道,在.NET里面,一旦加载了一个程序集,就永远没有办法卸载,除非你将整个AppDomain给卸了。这可真是一个远古的问题啊,想当年为此我们真是感觉非常的不爽。因为我们不得不为了一些场景而创建AppDomain,然后再这个Domain里面加载,然后做跨域调用,最后再卸载这个AppDomain。

 

但是到了.NET 4.0里面,一切就不一样了:在特定情况下,一个Assembly是可以被卸载的。是否很兴奋呢?嗯,别高兴太早,这可是有很多条件的。

 

条件

 

1、这个程序集必须是动态创建的,并且使用特殊参数;

2、这个可以动态卸载的程序集,里面所有的类,都不允许被静态引用(注意,不是指被静态程序集引用,而是指被派生等作为编码的一部分,参见二楼回复);

3、你不能明确要求卸载哪一个程序集,你只能要求GC回收所有对象(也就包括了不再使用的程序集);

4、这个动态程序集不可以被保存到磁盘上(这真是一个诡异的条件)。

 

解释

1、啥都不说了,直接上示例:

                    AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(

                        assemblyName,

                        AssemblyBuilderAccess.RunAndCollect

                    );

 也就是说,你必须使用这个新的枚举值RunAndCollect,那么这个程序集才能够被动态收集。反过来说,如果你想要有

 

2、这个需要稍微解释一下,那就是你在这个动态程序集A中创建出来的类,是不能被一个不可回收的(动态)程序集B中的类所继承的,因为这样就导致该程序集不可能被回收了。至于说能否作为B程序集中某个变量或者字段的类型,那这个我还真没有仔细考究,按照同样的逻辑,应该也是不行的。(这一条我还真没有认真考究,因为我的应用场景里面根本就没有这种可能性。)

 

3、可回收动态程序集的这个程序集本身,会被看作是一个普通的对象,如果这个对象中的任意部分存在引用计数,那么GC就不会回收。为啥不能有一个Unload方法来卸载呢?我想应该是如果存在这种方法的话,那就会大大增加了错误回收导致出现运行时错误的问题。 

 

4、这一条嘛,很明显RunAndCollect和RunAndSave是两个不同的枚举值,不能同时给出。至于原因,还真是觉得比较困惑。在我做测试的时候,还非得把这个参数改成RunAndSave然后才能保存,以便用Reflector看有什么地方写错了。为啥不让存呢?存了在加载就当作静态的好了。这个我也没有考究,因为我除了在调试的时候有可能需要保存下来看看之外,没有这种需要。

 

嗯,我承认,此文质量有所欠缺。那么,原谅我吧,我待会儿就要上火车了,所以没时间好好写写。不过呢,我还真搜了一下,似乎这是第一篇提到这个4.0新特性的中文帖子(至少在cnblogs里面是这样吧)。所以呢,我想在这里抛砖引玉,让大家找找4.0里面一些犄角旮旯里面的新东西,假如你有兴趣,甚至有应用需要的话。 


这里也给出一个EntityFramework的小题目,如果有兴趣,这些题目的实验结果也是比较有趣的。

 

假如有一个User表,包含以下字段: 

ID : int

Name : nvarchar

Description: nvarchar

 

表中数据如下:

1 A XXX

2 YYY

3 C ZZZ

 

那么,我们用EntityFramework构造好模型之后,能否做以下的查询:

var query = from item in Users

 select new object[] { item.Name, item.Description };

 

如果用下面这个做查询,会得到什么样的结果呢?(你会看到一个很有意思的Bug哦!)

var query = from item in Users

 select new List(){ item.Name, item.Description };

 

如果用下面这个做查询,又会有什么样的结果呢?

var query = from item in Users

 select new List(){ item.Name, item.Id };

 

为了抢占这个Bug的发现权,我先公布一下第二个查询的实际结果:

foreach(var item in query)

{

Console.WriteLine(item[0] + "," + item[1]);

输出:

A,XXX

YYY,B

C,ZZZ

 

为什么我会想到这些问题呢?这些问题又怎么会跟动态程序集的可回收联系在一起了呢?这是因为我需要做的一些很有趣的东西。

那么,这个有趣的东西又是什么呢?下一期的节目,更加精彩。 

posted on 2010-07-15 18:11  Sumtec  阅读(3274)  评论(12编辑  收藏  举报