/**/ /*********************************************** * 静态变量 * 在所属类装载时被创建; * 通过类(注意,是类,不是类的对象)进行访问; * 自始自终只存在一个值.***********************************************/ namespace 重要小知识点 // 静态变量 ... { class Program ...{ static int staNum = 0; //静态成员 public int pubNum = 10; //类成员 static void Main(string[] args) ...{ Program p = new Program(); p.pubNum = 100; //使用对象 访问类成员 Program.staNum = 999; //使用类名 访问静态成员 } }} /**/ /*********************************************** * const 和 static readonly * const 是在编译期间初始化 * static readonly 是在运行期间初始化 * 实验见 "C#基础概念二十五问"***********************************************/ namespace 重要小知识点 // const 和 static readonly ... { class Program ...{ public const int conNum = 100; public static readonly int srNum = 10000; static void Main(string[] args) ...{ Console.WriteLine(Program.conNum); //调用方法一样 Console.WriteLine(Program.srNum); //调用方法一样 } }} /**/ /*********************************************** * abstract * 此修饰可以用于类、方法、属性、事件和索引指示器. * 下面一段程序中需要注意的 * 抽象类中定义了一个Attribute,但它并不需要知道这是谁的属性; * 事件的定义方法,事件的响应函数,怎样触发一个事件; * 索引,可以对"对象"进行索引,也可以针对"成员"进行索引.***********************************************/ namespace 重要小知识点 // abstract ... { class Program ...{ public abstract class AMedia //抽象类 ...{ public abstract string Attribute //属性 ...{ get; set; } public abstract event EventHandler Play; //事件 注意写法 public abstract void Response(); public abstract string this[int Index] //索引 注意写法 ...{ get; } } public class Mp3 : AMedia ...{ //注意父抽象类,里面虽然有 Attribute属性,但却不需要定义 attribute变量 private string attribute; public override string Attribute //属性 ...{ get ...{ return attribute; } set ...{ attribute = value; } } public override event EventHandler Play; //事件 public override void Response() ...{ if (Play != null) ...{ Play(this, new EventArgs()); } } public override string this[int Index] //索引 ...{ get ...{ switch (Index) ...{ case 1: return "one"; case 2: return "two"; case 3: return "three"; default: return "rand"; } } } } static void OnPlay(object sender, EventArgs e) ...{ Console.WriteLine(" Mp3 is playing..."); } static void Main(string[] args) ...{ Mp3 mp3 = new Mp3(); mp3.Attribute = " HelloWorld!"; //使用属性 Console.WriteLine(mp3.Attribute); mp3.Play += new EventHandler(OnPlay); //与响应函数关联 mp3.Response();//触发事件 int i = 0; for (i = 0; i < 4; i++) ...{ Console.WriteLine(mp3[i]); //索引(针对 对象) } for (i = 0; i < mp3.Attribute.Length; i++) ...{ Console.WriteLine(mp3.Attribute[i]); //索引(针对 属性) } } }} /**/ /*********************************************** * sealed 密封 * 1) 用于类时,该类不能再被继承;(不能和abstract同用) * 2) 用于方法和属性时,该方法和属性不能被继承,必须和override * 连用,使用sealed修饰的方法肯定是基类中的 虚成员.***********************************************/ namespace 重要小知识点 // sealed ... { class Program ...{ static void Main(string[] args) ...{ A a = new A(); a.ShowMe(); B b = new B(); b.ShowMe(); } } sealed class SealSelf //此类无法再被继承 ...{ } class A ...{ public virtual void ShowMe() ...{ Console.WriteLine("I am A."); } } class B : A ...{ //密封的肯定是基类中的虚成员 public sealed override void ShowMe() //密封 ...{ Console.WriteLine("I am B."); } } class C : B ...{ }} /**/ /*********************************************** * 索引指示器 * 可以像数组那样使用其实例后的对象,但与数组不同的是 * 索引指示器的参数类型不仅限于int.***********************************************/ namespace 重要小知识点 ... { class Program ...{ private string secret; static void Main(string[] args) ...{ Program pro = new Program(); pro.Secret = "ILOVEU"; for (int i = 0; i < pro.Secret.Length; i++) //对类成员的索引操作 ...{ Console.WriteLine(pro.Secret[i]); } } public string this[int Index] //不仅限于int,可以是string Index等等 ...{ get ...{ return secret; } } public string Secret ...{ get ...{ return secret; } set ...{ secret = value; } } }} /**/ /*********************************************** * this * 关注该程序是如何测试效率的! * Environment.TickCount***********************************************/ namespace 重要小知识点 ... { class Program ...{ private string value; static void Main(string[] args) ...{ Program pro = new Program(); Console.WriteLine(pro.Test1()); Console.WriteLine(pro.Test2()); } public string Test1() ...{ long vTickCnt = Environment.TickCount; for (int i = 0; i < 10000000; i++) ...{ this.value = i.ToString(); //使用this调用成员 } return string.Format("Have this.:: {0} MSEL", Environment.TickCount - vTickCnt); } public string Test2() ...{ long vTickCnt = Environment.TickCount; for (int i = 0; i < 10000000; i++) ...{ value = i.ToString(); //不使用this调用成员 } return string.Format("Have this.:: {0} MSEL", Environment.TickCount - vTickCnt); } }} /**/ /*********************************************** * 可以使用抽象函数重写基类中的虚函数吗? * 答:可以. 需要使用 new 修饰符显式声明. * new:隐藏了基类中该函数的实现. * override:重新了基类中的函数.***********************************************/ namespace 重要小知识点 ... { class Program ...{ static void Main(string[] args) ...{ } } class Base ...{ public virtual void Show() ...{ Console.WriteLine("I am Base..."); } } abstract class Son : Base ...{ public new abstract void Show(); }} /**/ /*********************************************** * 密封类可以有虚函数吗? * 答:可以. 但基类中的虚函数隐式转换成非虚函数.***********************************************/ namespace 重要小知识点 ... { class Program ...{ static void Main(string[] args) ...{ } } class Base ...{ public virtual void Show() ...{ Console.WriteLine("I am Base..."); } } sealed class Son : Base ...{ // Base中的虚函数Show()已隐式转换为非虚函数了. //Son类不能自己再定义虚函数! }} /**/ /*********************************************** * 类和结构的区别 * 类是引用类型,在堆上分配,类的实例进行赋值其实只是复 * 制了引用; * 结构是值类型,在栈上分配,结构的赋值操作将产生一个新 * 对象. * * 堆和栈 * 堆:需要手动释放. 如类,如new * 栈:系统自动释放. 如函数里的变量***********************************************/ namespace 重要小知识点 ... { class Program ...{ static void Main(string[] args) ...{ OwnClass oc = new OwnClass("Hello"); OwnStruct os = new OwnStruct("Hello"); } } class OwnClass ...{ private string secret; public OwnClass(string str) ...{ //注意,这里的赋值操作. str 是一个引用类型, //所以不要再分配内存空间. this.secret = str; } } struct OwnStruct ...{ private string secret; //结构也可以有构造函数,但必须是有参数的构造函数. public OwnStruct(string str) ...{ //注意,这里的赋值操作. str 并非是一个引用类型, //所以得为它再分配内存空间. this.secret = str; } }} /**/ /*********************************************** * 接口的多继承会带来哪些问题? * 答:如果两个或多个父接口中存在同名成员,就产生二义性. * 此时,最好使用显式声明.***********************************************/ namespace 重要小知识点 ... { class Program : Video, Audio ...{ void Video.Play() //显式声明 ...{ Console.WriteLine("Video is working..."); } void Audio.Play() //显式声明 ...{ Console.WriteLine("Audio is working..."); } static void Main(string[] args) ...{ Program pro = new Program(); //注意如何调用 Video v = (Video)pro; //显示转换 v.Play(); Audio a = (Audio)pro; //显示转换 a.Play(); } } interface Video ...{ void Play(); } interface Audio ...{ void Play(); }} /**/ /*********************************************** * 抽象类和接口的区别: * 抽象类可以包含 定义 和 实现; * 接口只可以包含 定义. * * 抽象类是从一系列对象中抽象出来的概念,因此反映事物 * 的内部共性; * 接口是为了满足外部调用而定义的一个功能约定,因此反 * 映的是事物的外部特性. * * 分析对象,提炼内部共性形成抽象类,用以表示对象本质, * 即"是什么"; * 为外部提供调用或功能需要扩充时优先使用接口.***********************************************/ namespace 重要小知识点 ... { class Program ...{ static void Main(string[] args) ...{ } } abstract class Base ...{ public abstract void Show(); public void Hide() //抽象类可以有已实现的成员 ...{ Console.WriteLine("have hided..."); } } class Son : Base ...{ public override void Show() ...{ Console.WriteLine("I am Base's son..."); } }} /**/ /*********************************************** * using 别名指示符 * 包含其它文件,为某个类型起个别名; * 只在一个单元文件内起作用.***********************************************/ namespace 重要小知识点 ... { class Program ...{ static void Main(string[] args) ...{ T1.Test1 t1 = new T1.Test1(); //T1 是 Test1.cs 的别名 t1.Show(); T2.Test2 t2 = new T2.Test2(); t2.Show(); } }} /**/ /*********************************************** * StringBuilder和String的区别 * String虽然是引用类型,但在赋值时却会产生新的对象; * StringBuilder则不会,所以在处理大量字符串时,它是首选.***********************************************/ namespace 重要小知识点 ... { class Program ...{ static void Main(string[] args) ...{ Program pro = new Program(); pro.Test1(); pro.Test2(); } public void Test1() ...{ long vTickCnt = Environment.TickCount; string str = null; for (int i = 0; i < 20000; i++) ...{ str += i.ToString(); } Console.WriteLine("string 字符串相加需要 {0} 毫秒", Environment.TickCount - vTickCnt); } public void Test2() ...{ long vTickCnt = Environment.TickCount; StringBuilder sb = new StringBuilder(); for (int i = 0; i < 20000; i++) ...{ sb.Append(i); } Console.WriteLine("StringBuilder 字符串相加需要 {0} 毫秒", Environment.TickCount - vTickCnt); } }} /**/ /*********************************************** * params * 该关键字用在方法的参数列表中,为该方法参数提供了可 * 变的能力.它只能出现一次,且只能定义在所有参数最后.***********************************************/ namespace 重要小知识点 ... { class Program ...{ //params 定义的参数后面不可以再定义其它参数 public static void UseParams(string str, params object[] list) ...{ Console.WriteLine(str); for (int i = 0; i < list.Length; i++) ...{ Console.WriteLine(list[i]); } } static void Main(string[] args) ...{ String[] str = new string[] ...{ "I", "LOVE", "YOU" }; Program.UseParams("Hello", str); } }}