千家信息网

C#中使用CLR需要注意什么

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,这篇文章主要为大家展示了"C#中使用CLR需要注意什么",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"C#中使用CLR需要注意什么"这篇文章吧。1、C# C
千家信息网最后更新 2026年11月02日C#中使用CLR需要注意什么

这篇文章主要为大家展示了"C#中使用CLR需要注意什么",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"C#中使用CLR需要注意什么"这篇文章吧。

1、C# CLR之foreach的性能问题

foreach(string s in rows) { foo(s); }的实现是:

IEnumerator e = rows.GetEnumerator();  try {    string s;    while (e.MoveNext()) {      s = (String) e.Current;      foo(s);    }  }  finally {    IDisposable d = e as IDisposable;    if (d != null) d.Dispose();  }

每一步都调用了e.MoveNext()和e.Current两个方法;而大多数时候,完全有可能优化为一次调用。显然这对性能是有影响的。虽然foreach对于数组作了单独的优化(编译成for循环),但这还是值得注意的。

那么,怎么做比较快?

对于List等Collection,可以用ForEach(Actionaction),FindAll(Predicatematch),ConvertAll(Converterconverter)等方法。它们比较快,但不是所有实现IEnumerable的类都提供。

LINQ追求compatiblity,而不是performance。因此LINQ的实现完全采用了foreach。值得注意。

2、C# CLR之yield的实现原理

实现一个支持IEnumerable的对象时,一般会用到yield关键字,这样foreach遍历这个对象时,可以做到lazy evaluation。例如:

class MyCollection: IEnumerable {    private string s; ...    public IEnumerable GetEnumerator() {      for (int i=0; i

执行到yield时函数返回,下次调用时,接着上次运行的位置继续运行。这个continuation的效果是怎么做的呢?

包含yield的函数都会被编译器做成一个状态机。每调一次,就接着上次的状态继续运行。简单有效啊。我一直以为要有什么特殊的办法呢。

3、C# CLR之exception handling的实现决定了throw的performance较差。

可以用Int32.TryParse代替try{Int32.Parse…}catch{…},稍快一点。类似地建议使用Dictionary.TryGetValue。

4、C# CLR之.Net CLR执行引擎对应于MSCorWks.dll和MSCorEE.dll这两个文件。

5、C# CLR之.Net 3.0, 3.5没有对CLR作任何修改。

所有增加的东西(比如LINQ)都是syntactic sugar,只改了C#编译器而已。

6、C# CLR之AppDomain

如果把.Net虚拟机看成一个虚拟操作系统,AppDomain的概念则类似于操作系统中的进程。

可以用代码创建一个AppDomain,然后动态加载/卸载assembly,还可以设置权限,相当于提供了一个沙箱。

跨AppDomain的调用类似于RPC。

调用某个AppDomain内部的obj.foo(x)时,.net会自动帮你做出一个proxy object,你所调用的obj其实是一个proxy object。传给foo的参数x会先被被marshal,以保证AppDomain被安全隔离。

谁用AppDomain?SQL Server用这个技术实现managed存储过程。IIS会把不同的Web Application放在不同的AppDomain里,以实现动态装卸。

7、C# CLR之动态载入Assembly的陷阱

Sytem.Reflection.Assembly.LoadFrom(pathName)并不会载入pathName所指定的dll,而是看看pathName那个dll的名字、版本,然后到系统默认位置去找。(陷阱啊)

8、C# CLR之C#里用reflection创建一个新对象

用Activator.CreateInstance。(奇怪的名字啊。)

9、C# CLR之C#泛型之"where"

可以用"where"来限定T的接口。例如

static T min(T arg1, T arg2) where T: IComparable{…}

不写where的话,就不能调arg1.CompareTo(arg2)。

为啥不把T换成IComparable?一是为保证arg1, arg2一定是同一个类型,二是泛型的效率更高。(JIT会为不同类型的T各生成一份native code,从而避免了boxing)

更多where的细节:

* 要想调T t1 = new T(),必须声明where T: new()或者where T: struct

* 要写T t2 = null,必须声明where T: class

* T z = default(T)是一个特殊的用法,会把T的每个bit都置为0。

* 假设定义了Foo(T x, T y),则if (x==null) … 是可以通过的,虽然C#中value type的值不允许为null(例如int a=null是错的)。这是因为,此时的语义是一致的,反正if里面的操作不被执行就是了,所以编译器对这种特殊情况网开一面。

* if (x==y)不行,除非写了where T: baseclass。(这里我也没理解为啥。。。>_<好像说是不知道应该用reference比较还是value比较?)

10、C# CLR之匿名函数的背后。。。

在C# 2.0以后可以用匿名的delegate,如ThreadPool.QueueWorkItem(delegate (Object obj) { Console.WriteLine(obj); })

但编译器的实现会带来一点点overhead,会生成一个小小的静态WaitCallback对象,可以用Reflector看生成的代码。(不要打开Reflector的optimization,否则就看不到了)

如果是自己写的话,可以选择每次动态建立一个WaitCallback对象然后销毁。当然这样做性能可能差一些,但这里的idea是:编译器会自动做一些事,但不一定是你所希望的。在使用这些高级feature前,最好先搞清楚背后发生了什么。

另一个细节:如果匿名函数中使用了外层函数的局部变量(即所谓的function closure),会导致创建额外的shared-state object,把用到的局部变量做成一个新对象传给匿名函数。

上述描述同样适用于lambda函数。因为C#的lambda函数就是匿名函数,改了改语法而已。

11、C# CLR之Nullable type

虽然C#要求value type的值不能是null,但写数据库程序时经常遇到某个值是null的情况。为此,C#2.0引入了Nullable type。例如,int? x = null。

int? x其实就是一个缩写,等价于Nullablex。Nullable是预定义的一个类,简单地对x作了封装。(因为增加了一个类,显然对性能稍微有点影响)

这个小改动的实现其实很麻烦,需要修改CLR。为什么?因为原先的x是一个value type,现在则变成了一个object,看这个:

void M(Object o)   {    if (o=null) {Bar();}  }  void F()  {    int? x = null;    M(x);  }

如果CLR不专门做修正的话,上面的Bar()不会被执行。(思考题:想一想为什么~)

另外,C#还引入了一个默认值运算符"??",称为null-coalescing operator。

一句话,x ?? value是 (x==null) ? value: x的简写。

12、C# CLR之属性(property)的简单声明

public int x {get; private set;}

是个很好用的句式。

注意,

public int x {get;}

是错误的,不能通过编译。

13、C# CLR之Extension method

//Extension method  static class MyExtMethods   {    static public GetFirstLetter(this string s) {return s[0];}  }

然后就可以用string s = "hello"; char ch = s.GetFirstLetter()了。

原理很简单,编译器把上面那句话翻译成MyExtMethods.GetFirstLetter(s)。LINQ就用到了这个技术。

14、C# CLR之匿名类型的背后。。。

var o = new {name = "Xiangpeng", id = 123 };

在这背后是编译器生成的一个匿名类,包含了两个只读属性,形如public int id { get {return _id;} }为什么不做成可读写的呢?

很微妙。匿名类自动生成了GetHashCode(),返回的是对所有属性的hash code做XOR的结果。如果允许修改属性值,那么Hash code的值就会变化;而这个可能会出问题~保险起见,只读吧。

15、C# CLR之每个thread占1M物理内存

在Win32编程中thread的1M stack空间是Reserve的,直到真正用时才占用物理内存;而在.net中,这1M空间直接被commit。

还好,可以在新建thread时指定stack size。不过这也比较危险,设小了怕不够。实际上,最好尽量避免创建thread--太多的thread要么导致CPU竞争和context switch,要么都block着浪费内存。建议是:能用ThreadPool就用ThreadPool。

以上是"C#中使用CLR需要注意什么"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

C# 函数 编译 编译器 对象 生成 动态 属性 性能 背后 不同 特殊 两个 内存 内容 就是 篇文章 类型 系统 运行 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 保险科技 互联网保险 互联网是第几次科技革命的成果 山东特亿宝互联网科技有限公司 广州百单互联网科技有限公司 上海互联网科技有限公司 科技与互联网发展 嘟嘟瓜互联网科技 互联网科技媒体 互联网 新科技 成都狮子座互联网科技 互联网科技有限公司 翻译 互联网科技公司的市场部门 玖二柒互联网科技公司待遇 互联网5g黑科技有哪些 本届互联网博览会上的黑科技 世界互联网领先科技成果获奖 广州有谷有贝互联网科技有限公司 互联网科技手机排行榜 恒生互联网科技趋势 宁波允成互联网科技有限公司 工业互联网科技新基建 互联网科技有限公司图片 互联网最新的科技有限公司 成都互联网科技公司 贷财互联网科技 壕鑫互联网络科技 郑州华宇互联网科技 米聚互联网科技南京有限公司排面 有人说阿里系是互联网科技企业 互联网科技创新方面的资料
0