(转贴)DotNet框架编程 读书笔记

      今天早上, 我读完了第二章, 感觉以上评论决不为过. 本书对 CLR等底层的讲述 之透彻, 绝非两句"wonderful"可以表述.  在此我想谈谈我对 CLR 在跨语言方面的理解.

首先 CLR的功能是建立在 CLR类型(CTS CommonTypeSystem) 的基础之上, 每种具体的.Net语言(如C#,J#等)的类型都是 CLR类型 的子集.

然后 当你用某种语言 写了一段代码后,有各种语言的编译器 把其编译成IL(例如csc.exe 把你的 .cs文件编译成能够受 CLR 支持的IL.)  无论你在某种语言使用的何种数据类型,变量,方法,事件 都会在IL表示为 属性和操作(在IL中只有这两种表示)

最后 当你IL的这种 属性和操作 是都能够被 各种语言所识别使用的.(这样就避免的C#的类型不能被VB.net识别的问题了)

昨天晚上,看了一下 class和struct的比较.简单谈一下自己的体会

在本书中,首先谈到在c++等语言中是有struct的.而Java是一个精简基本类的编程语言,Java没有提供struct类型(字所有去处这种类型,是因为struct完全可以有class来实现).
然后又谈到c# 在很大程度上参考了Java(这个还又说,地球人都知道了:)).但是又把struct从c++中托了回来, 这究竟为什么呢?

原来struct是值类型使用,而class是引用类型使用.建立struct的时候是在栈上分配内存,而class是在托管堆上分配内存. 这样差别就出来了: 当向栈上push的时候分配一块内存,当从栈上pop的时候内存自动释放.  而在clr的托管堆上就不同了,当你new一个class成一个object的时候分配一块内存. 但是当你使用完本对象销毁的时候,内存空间是 不能实时释放的.要等GC不定时间进行收集. 这个内存收集过程又会占有很大一部分资源(关于内存收集方面的内容,本论坛内有其他几篇文章论述).

所有出于性能方面的考虑 我们在写程序的时候能构使用struct的地方,就尽量不要使用class

关于类型转换中的 is和as的使用

is作为运算符出现在类型转换中的.其作用是检查对象的运行时类型是否与给定类型兼容,在这种类型兼容性判定中要进行一次类型转换. 然后根据类型的兼容性进行其他处理工作.

AS 也是一个运算符, 对某个对象进行 as操作后 分为两种情况 1.如果类型兼容 操作成功 就会返回 as后的新类型 2.如果操作失败就会返回null.

 这样就可以看出两操作符的 性能比较了.比如我原来 使用FindControl()方法 根据一个 变量名称的string 去获取这个变量时 是这么写的:

if(this.FindControl("myCheck") is System.CheckBox) //M处
{
  System.CheckBox tempCheck= (System.CheckBox)this.FindControl("myCheck");//N处
  tempCheck.Checked= true;
}

很明显以上操作在M和N处分别进行了 两次类型转换.

如果现在改成这么写

System.CheckBox tempCheck= this.FindControl("myCheck") as System.CheckBox;//L处
if(tempCheck!=null
{
  tempCheck.Checked= true;
}

现在就只是在L处 进行了一次类型转换.

类型转换在CLR中,是比较消耗性能的, 现在大家应该知道怎么办了吧.(至少我以后不会用第一中方法了)

最近几天晚上 一直都在喝酒,没有空看书. 昨晚好不容易看了一点关于 类构造器得问题(同时 前些天也跟刘**谈论过这个问题).那就是一个类可不可以没有构造函数. 先看这段代码: using System;
namespace Xieran.Test
{
 public class App
 {
  static public void Main(System.String[] args)
  {
   System.Console.WriteLine("Hi,Mr.Liuxd!");
   System.Console.ReadLine();
  }
 }
}
其编译是可以通过 并且可以得到预想得答案数据.     好像一个类没有构造函数也可以得.  难道这是真得么?  通过ILDasm查看IL 代码如下:

 

可以看到 .ctor():void  ,这个便是IL里面得类得构造函数. 呵呵 原来是CSC在编译我们代码得时候 自动加了一个 构造函数. 自此,一个类得构造函数是不是必须得 就不言自明

关于值类型和引用类型的理解

.NET CLR中有两种数据类型 值类型和引用类型. 其中值类型是一种简单的数据类型 其是在 应用程序的线程栈上进行分配和即时内存回收的. 引用类型 是在CLR托管堆上进行内存分配的, 同时其在托管堆上分配的地址被记录在 应用程序的线程栈上, 最后他的内存回收不是即时的 其是有GC进行不定时的收集.

.NET中所有的类型 都继承于System.Object, 当然值类型也是如此. 不过值类型是通过继承ValueType类型间接的继承于Sytem.Object.   继承或间接继承于System.Object的类都是 引用类型(有特例) 包括ValueType类型. 但是经过ValueType类型的处理(具体怎么处理的我也不清楚:( ),继承于ValueType的类 便成了 值类型(有点奇怪 从引用类型继承下来的东西成了 值类型 :( ).  而有ValueType继承得到的值类型, 便不内为其他值类型的基类了,也就是说所有的值类型 都是直接继承于 ValueType.(值类型不能被继承着个也不奇怪, 继承是引用类型的专利 因为子类在获取父类的方法 属性的时候 需要使用的 应用表 只有在引用类型中才有的. )

关于String和StringBuilder的使用
前些天作一个项目 需要安装客户提供的Excel样式,打印输入同样的报表(初接项目时 巨汗),后来与同事探讨打算 以原Excel作为模板, 然后读入此Excel的全部内容(包括样式等信息) 在程序后台 对此Excel每个cell内的内容 通过读取数据库进行替换. 最后再把替换后的 Excel 文件 通过Response刷向客户端. ----呵呵,这绝对是一个很好的创意(否则,如何才能保证和客户要求的Excel样式完全一样?).

写了个模板读取引擎(其专门负责读取客户提供的Excel文件) ,最初 读取后的数据存放在一个string中,然后每次 利用string的Replace方法逐一替换数值. 要知道客户交给我们的Excel文件有5个多k大小. 其中要替换900次. 这个有点危言耸听把 呵呵. 当我还没有替换完成 系统就崩溃了. 有副图片大家可以看看

内存从300多M一路上杨到800多M, 然后突然崩溃(就在内存突然降低处).

看来这个方法不行. 然后想到了StringBuilder, 这次把模板引擎读取的数据直接保持在StringBuilder中,然后调用StringBuilder的Replace方法进行 这900次替换.  呵呵 看看内存的使用情况把


从图上可以清楚地看出在cpu100%运行的地方内存甚至还有所下降(不知道为什么会下降,我执行了号几次都是内存会下降 --我怀疑每每在此时都有内存收集).

现在改轮到解释一下 这种现象的本质了:
string对象一旦创建 便会在内存中”稳定”的存在.他的大小长度永远不会被改变. 比如你使用
string s=”Hello”;
s.ToLower();
那么会是这杨,首先在内存中创建一个字符川s, 然后当你ToLower()的时候, 一个小写的”hello”会是重新分配一块内存, 而这块内存与 小s占用内存已经没有任何关系了.  在我的第一段程序中,这900次替换 每次都要 重新分配一次内存 . 而分配内存的过程是要好用时间的. 同时新内存分配后,旧内存并没有实时释放, 所以会出现 系统崩溃的情形了.

而StringBuilder就不同了, StringBuilder每次Replace的时候 都是在他自己本身上进行的. 不需要另外分配内存 这样季不占有内存分配时的时间 也不占有内存空间.所以会出现 下面一副 比较”赏心悦目”的图了.

由此可见,操作大的字符串,尤其是 在字符串上频繁的有操作时 尤其应该使用StringBuilder了

//======================================================

也谈const VS readonly

这个问题前些天 与很多人都讨论过. 其中吴**的结论是 const定义的常量是属于类型的 而readonly定义的只读变量是属于 实例的. "框架编程"则本书上 也有对此问题的 说明. 下面我将通过代码 及其编译后的IL 阐述一些这个问题.
namespace  xieran.Test
{
    
public class myClass
    
{
        
const string myName= "Liuxd";
        
private readonly string myScholl="QDU";

        
static public void Main(System.String[] args)
        
{
            System.Console.WriteLine(
"Hi,Mr.Liuxd!");
            System.Console.ReadLine();
        }

    }

}

当把上面的代码编译后 查看MSIL

可以看到定义为const的myName在IL中变成了一个static的字符串了, 静态的东西是属于类型的.而定义为readonly的myScholl是属于对象的 (吴**说的是正确的:))

在上面的代码中 我在加一句 静态的变量myGame如下:
namespace  xieran.Test
{
    
public class myClass
    
{
        
const string myName= "Liuxd";
        
static string myGame= "footBall";
        
private readonly string myScholl="QDU";

        
static public void Main(System.String[] args)
        
{
            System.Console.WriteLine(
"Hi,Mr.Liuxd!");
            System.Console.ReadLine();
        }

    }

}

在看编译后的MSIL的情况

可以看到除了增加了一个静态的变量myGame外,csc编译器还自动增加了一个类型构造器(.cctor---class constructor). 打开此类型构造器看到IL如下:

.method private hidebysig specialname rtspecialname static
        void  .cctor() cil managed
{
  // 代码大小       11 (0xb)
  .maxstack  1
  IL_0000:  ldstr      "footBall"
  IL_0005:  stsfld     string xieran.Test.myClass::myGame
  IL_000a:  ret
} // end of method myClass::.cctor

也就是说在代码中声明的静态字段 是在类型构造器中初始化的, 声明的const显然没有在类型构造器中初始化.

在myName上双击打开其代码 为
.field private static literal string myName = "Liuxd"
在myGame上打开其代码为
.field private static string myGame
也就是说常量是在编译时确定其值的. 各种变量(包括static变量)是在运行时 通过构造器(实例构造器或类型构造器)进行初始化的. 常量在编译后其值是放在模块的元数据中的. 同时由于常数是在编译时初始化,所有其 能够支持的数据类型也是有限的(其类型必须是编译器认识的“基元类型“如Int32,String等,至于其他的各种类型就不支持了).

关于String和StringBuilder的使用
前些天作一个项目 需要安装客户提供的Excel样式,打印输入同样的报表(初接项目时 巨汗),后来与同事探讨打算 以原Excel作为模板, 然后读入此Excel的全部内容(包括样式等信息) 在程序后台 对此Excel每个cell内的内容 通过读取数据库进行替换. 最后再把替换后的 Excel 文件 通过Response刷向客户端. ----呵呵,这绝对是一个很好的创意(否则,如何才能保证和客户要求的Excel样式完全一样?).

写了个模板读取引擎(其专门负责读取客户提供的Excel文件) ,最初 读取后的数据存放在一个string中,然后每次 利用string的Replace方法逐一替换数值. 要知道客户交给我们的Excel文件有5个多k大小. 其中要替换900次. 这个有点危言耸听把 呵呵. 当我还没有替换完成 系统就崩溃了. 有副图片大家可以看看

内存从300多M一路上杨到800多M, 然后突然崩溃(就在内存突然降低处).

看来这个方法不行. 然后想到了StringBuilder, 这次把模板引擎读取的数据直接保持在StringBuilder中,然后调用StringBuilder的Replace方法进行 这900次替换.  呵呵 看看内存的使用情况把


从图上可以清楚地看出在cpu100%运行的地方内存甚至还有所下降(不知道为什么会下降,我执行了号几次都是内存会下降 --我怀疑每每在此时都有内存收集).

现在改轮到解释一下 这种现象的本质了:
string对象一旦创建 便会在内存中”稳定”的存在.他的大小长度永远不会被改变. 比如你使用
string s=”Hello”;
s.ToLower();
那么会是这杨,首先在内存中创建一个字符川s, 然后当你ToLower()的时候, 一个小写的”hello”会是重新分配一块内存, 而这块内存与 小s占用内存已经没有任何关系了.  在我的第一段程序中,这900次替换 每次都要 重新分配一次内存 . 而分配内存的过程是要好用时间的. 同时新内存分配后,旧内存并没有实时释放, 所以会出现 系统崩溃的情形了.

而StringBuilder就不同了, StringBuilder每次Replace的时候 都是在他自己本身上进行的. 不需要另外分配内存 这样季不占有内存分配时的时间 也不占有内存空间.所以会出现 下面一副 比较”赏心悦目”的图了.

由此可见,操作大的字符串,尤其是 在字符串上频繁的有操作时 尤其应该使用StringBuilder了

//======================================================

也谈const VS readonly

这个问题前些天 与很多人都讨论过. 其中吴**的结论是 const定义的常量是属于类型的 而readonly定义的只读变量是属于 实例的. "框架编程"则本书上 也有对此问题的 说明. 下面我将通过代码 及其编译后的IL 阐述一些这个问题.
namespace  xieran.Test
{
    
public class myClass
    
{
        
const string myName= "Liuxd";
        
private readonly string myScholl="QDU";

        
static public void Main(System.String[] args)
        
{
            System.Console.WriteLine(
"Hi,Mr.Liuxd!");
            System.Console.ReadLine();
        }

    }

}

当把上面的代码编译后 查看MSIL

可以看到定义为const的myName在IL中变成了一个static的字符串了, 静态的东西是属于类型的.而定义为readonly的myScholl是属于对象的 (吴**说的是正确的:))

在上面的代码中 我在加一句 静态的变量myGame如下:
namespace  xieran.Test
{
    
public class myClass
    
{
        
const string myName= "Liuxd";
        
static string myGame= "footBall";
        
private readonly string myScholl="QDU";

        
static public void Main(System.String[] args)
        
{
            System.Console.WriteLine(
"Hi,Mr.Liuxd!");
            System.Console.ReadLine();
        }

    }

}

在看编译后的MSIL的情况

可以看到除了增加了一个静态的变量myGame外,csc编译器还自动增加了一个类型构造器(.cctor---class constructor). 打开此类型构造器看到IL如下:

.method private hidebysig specialname rtspecialname static
        void  .cctor() cil managed
{
  // 代码大小       11 (0xb)
  .maxstack  1
  IL_0000:  ldstr      "footBall"
  IL_0005:  stsfld     string xieran.Test.myClass::myGame
  IL_000a:  ret
} // end of method myClass::.cctor

也就是说在代码中声明的静态字段 是在类型构造器中初始化的, 声明的const显然没有在类型构造器中初始化.

在myName上双击打开其代码 为
.field private static literal string myName = "Liuxd"
在myGame上打开其代码为
.field private static string myGame
也就是说常量是在编译时确定其值的. 各种变量(包括static变量)是在运行时 通过构造器(实例构造器或类型构造器)进行初始化的. 常量在编译后其值是放在模块的元数据中的. 同时由于常数是在编译时初始化,所有其 能够支持的数据类型也是有限的(其类型必须是编译器认识的“基元类型“如Int32,String等,至于其他的各种类型就不支持了).

关于值类型和引用类型的理解

.NET CLR中有两种数据类型 值类型和引用类型. 其中值类型是一种简单的数据类型 其是在 应用程序的线程栈上进行分配和即时内存回收的. 引用类型 是在CLR托管堆上进行内存分配的, 同时其在托管堆上分配的地址被记录在 应用程序的线程栈上, 最后他的内存回收不是即时的 其是有GC进行不定时的收集.

.NET中所有的类型 都继承于System.Object, 当然值类型也是如此. 不过值类型是通过继承ValueType类型间接的继承于Sytem.Object.   继承或间接继承于System.Object的类都是 引用类型(有特例) 包括ValueType类型. 但是经过ValueType类型的处理(具体怎么处理的我也不清楚:( ),继承于ValueType的类 便成了 值类型(有点奇怪 从引用类型继承下来的东西成了 值类型 :( ).  而有ValueType继承得到的值类型, 便不内为其他值类型的基类了,也就是说所有的值类型 都是直接继承于 ValueType.(值类型不能被继承着个也不奇怪, 继承是引用类型的专利 因为子类在获取父类的方法 属性的时候 需要使用的 应用表 只有在引用类型中才有的. )

关于String和StringBuilder的使用
前些天作一个项目 需要安装客户提供的Excel样式,打印输入同样的报表(初接项目时 巨汗),后来与同事探讨打算 以原Excel作为模板, 然后读入此Excel的全部内容(包括样式等信息) 在程序后台 对此Excel每个cell内的内容 通过读取数据库进行替换. 最后再把替换后的 Excel 文件 通过Response刷向客户端. ----呵呵,这绝对是一个很好的创意(否则,如何才能保证和客户要求的Excel样式完全一样?).

写了个模板读取引擎(其专门负责读取客户提供的Excel文件) ,最初 读取后的数据存放在一个string中,然后每次 利用string的Replace方法逐一替换数值. 要知道客户交给我们的Excel文件有5个多k大小. 其中要替换900次. 这个有点危言耸听把 呵呵. 当我还没有替换完成 系统就崩溃了. 有副图片大家可以看看

内存从300多M一路上杨到800多M, 然后突然崩溃(就在内存突然降低处).

看来这个方法不行. 然后想到了StringBuilder, 这次把模板引擎读取的数据直接保持在StringBuilder中,然后调用StringBuilder的Replace方法进行 这900次替换.  呵呵 看看内存的使用情况把


从图上可以清楚地看出在cpu100%运行的地方内存甚至还有所下降(不知道为什么会下降,我执行了号几次都是内存会下降 --我怀疑每每在此时都有内存收集).

现在改轮到解释一下 这种现象的本质了:
string对象一旦创建 便会在内存中”稳定”的存在.他的大小长度永远不会被改变. 比如你使用
string s=”Hello”;
s.ToLower();
那么会是这杨,首先在内存中创建一个字符川s, 然后当你ToLower()的时候, 一个小写的”hello”会是重新分配一块内存, 而这块内存与 小s占用内存已经没有任何关系了.  在我的第一段程序中,这900次替换 每次都要 重新分配一次内存 . 而分配内存的过程是要好用时间的. 同时新内存分配后,旧内存并没有实时释放, 所以会出现 系统崩溃的情形了.

而StringBuilder就不同了, StringBuilder每次Replace的时候 都是在他自己本身上进行的. 不需要另外分配内存 这样季不占有内存分配时的时间 也不占有内存空间.所以会出现 下面一副 比较”赏心悦目”的图了.

由此可见,操作大的字符串,尤其是 在字符串上频繁的有操作时 尤其应该使用StringBuilder了

//======================================================

也谈const VS readonly

这个问题前些天 与很多人都讨论过. 其中吴**的结论是 const定义的常量是属于类型的 而readonly定义的只读变量是属于 实例的. "框架编程"则本书上 也有对此问题的 说明. 下面我将通过代码 及其编译后的IL 阐述一些这个问题.
namespace  xieran.Test
{
    
public class myClass
    
{
        
const string myName= "Liuxd";
        
private readonly string myScholl="QDU";

        
static public void Main(System.String[] args)
        
{
            System.Console.WriteLine(
"Hi,Mr.Liuxd!");
            System.Console.ReadLine();
        }

    }

}

当把上面的代码编译后 查看MSIL

可以看到定义为const的myName在IL中变成了一个static的字符串了, 静态的东西是属于类型的.而定义为readonly的myScholl是属于对象的 (吴**说的是正确的:))

在上面的代码中 我在加一句 静态的变量myGame如下:
namespace  xieran.Test
{
    
public class myClass
    
{
        
const string myName= "Liuxd";
        
static string myGame= "footBall";
        
private readonly string myScholl="QDU";

        
static public void Main(System.String[] args)
        
{
            System.Console.WriteLine(
"Hi,Mr.Liuxd!");
            System.Console.ReadLine();
        }

    }

}

在看编译后的MSIL的情况

可以看到除了增加了一个静态的变量myGame外,csc编译器还自动增加了一个类型构造器(.cctor---class constructor). 打开此类型构造器看到IL如下:

.method private hidebysig specialname rtspecialname static
        void  .cctor() cil managed
{
  // 代码大小       11 (0xb)
  .maxstack  1
  IL_0000:  ldstr      "footBall"
  IL_0005:  stsfld     string xieran.Test.myClass::myGame
  IL_000a:  ret
} // end of method myClass::.cctor

也就是说在代码中声明的静态字段 是在类型构造器中初始化的, 声明的const显然没有在类型构造器中初始化.

在myName上双击打开其代码 为
.field private static literal string myName = "Liuxd"
在myGame上打开其代码为
.field private static string myGame
也就是说常量是在编译时确定其值的. 各种变量(包括static变量)是在运行时 通过构造器(实例构造器或类型构造器)进行初始化的. 常量在编译后其值是放在模块的元数据中的. 同时由于常数是在编译时初始化,所有其 能够支持的数据类型也是有限的(其类型必须是编译器认识的“基元类型“如Int32,String等,至于其他的各种类型就不支持了).

关于String和StringBuilder的使用
前些天作一个项目 需要安装客户提供的Excel样式,打印输入同样的报表(初接项目时 巨汗),后来与同事探讨打算 以原Excel作为模板, 然后读入此Excel的全部内容(包括样式等信息) 在程序后台 对此Excel每个cell内的内容 通过读取数据库进行替换. 最后再把替换后的 Excel 文件 通过Response刷向客户端. ----呵呵,这绝对是一个很好的创意(否则,如何才能保证和客户要求的Excel样式完全一样?).

写了个模板读取引擎(其专门负责读取客户提供的Excel文件) ,最初 读取后的数据存放在一个string中,然后每次 利用string的Replace方法逐一替换数值. 要知道客户交给我们的Excel文件有5个多k大小. 其中要替换900次. 这个有点危言耸听把 呵呵. 当我还没有替换完成 系统就崩溃了. 有副图片大家可以看看

内存从300多M一路上杨到800多M, 然后突然崩溃(就在内存突然降低处).

看来这个方法不行. 然后想到了StringBuilder, 这次把模板引擎读取的数据直接保持在StringBuilder中,然后调用StringBuilder的Replace方法进行 这900次替换.  呵呵 看看内存的使用情况把


从图上可以清楚地看出在cpu100%运行的地方内存甚至还有所下降(不知道为什么会下降,我执行了号几次都是内存会下降 --我怀疑每每在此时都有内存收集).

现在改轮到解释一下 这种现象的本质了:
string对象一旦创建 便会在内存中”稳定”的存在.他的大小长度永远不会被改变. 比如你使用
string s=”Hello”;
s.ToLower();
那么会是这杨,首先在内存中创建一个字符川s, 然后当你ToLower()的时候, 一个小写的”hello”会是重新分配一块内存, 而这块内存与 小s占用内存已经没有任何关系了.  在我的第一段程序中,这900次替换 每次都要 重新分配一次内存 . 而分配内存的过程是要好用时间的. 同时新内存分配后,旧内存并没有实时释放, 所以会出现 系统崩溃的情形了.

而StringBuilder就不同了, StringBuilder每次Replace的时候 都是在他自己本身上进行的. 不需要另外分配内存 这样季不占有内存分配时的时间 也不占有内存空间.所以会出现 下面一副 比较”赏心悦目”的图了.

由此可见,操作大的字符串,尤其是 在字符串上频繁的有操作时 尤其应该使用StringBuilder了

//======================================================

也谈const VS readonly

这个问题前些天 与很多人都讨论过. 其中吴**的结论是 const定义的常量是属于类型的 而readonly定义的只读变量是属于 实例的. "框架编程"则本书上 也有对此问题的 说明. 下面我将通过代码 及其编译后的IL 阐述一些这个问题.
namespace  xieran.Test
{
    
public class myClass
    
{
        
const string myName= "Liuxd";
        
private readonly string myScholl="QDU";

        
static public void Main(System.String[] args)
        
{
            System.Console.WriteLine(
"Hi,Mr.Liuxd!");
            System.Console.ReadLine();
        }

    }

}

当把上面的代码编译后 查看MSIL

可以看到定义为const的myName在IL中变成了一个static的字符串了, 静态的东西是属于类型的.而定义为readonly的myScholl是属于对象的 (吴**说的是正确的:))

在上面的代码中 我在加一句 静态的变量myGame如下:
namespace  xieran.Test
{
    
public class myClass
    
{
        
const string myName= "Liuxd";
        
static string myGame= "footBall";
        
private readonly string myScholl="QDU";

        
static public void Main(System.String[] args)
        
{
            System.Console.WriteLine(
"Hi,Mr.Liuxd!");
            System.Console.ReadLine();
        }

    }

}

在看编译后的MSIL的情况

可以看到除了增加了一个静态的变量myGame外,csc编译器还自动增加了一个类型构造器(.cctor---class constructor). 打开此类型构造器看到IL如下:

.method private hidebysig specialname rtspecialname static
        void  .cctor() cil managed
{
  // 代码大小       11 (0xb)
  .maxstack  1
  IL_0000:  ldstr      "footBall"
  IL_0005:  stsfld     string xieran.Test.myClass::myGame
  IL_000a:  ret
} // end of method myClass::.cctor

也就是说在代码中声明的静态字段 是在类型构造器中初始化的, 声明的const显然没有在类型构造器中初始化.

在myName上双击打开其代码 为
.field private static literal string myName = "Liuxd"
在myGame上打开其代码为
.field private static string myGame
也就是说常量是在编译时确定其值的. 各种变量(包括static变量)是在运行时 通过构造器(实例构造器或类型构造器)进行初始化的. 常量在编译后其值是放在模块的元数据中的. 同时由于常数是在编译时初始化,所有其 能够支持的数据类型也是有限的(其类型必须是编译器认识的“基元类型“如Int32,String等,至于其他的各种类型就不支持了).

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值