注:本文部份資料來自網(wǎng)絡(luò),如有侵權(quán),請與我聯(lián)系,我會在第一時(shí)間聲明引用或?qū)⑵鋭h除! 當(dāng)初學(xué) C# 時(shí)是找個(gè)人大概問了一下數(shù)據(jù)類型和分支語句就開始做項(xiàng)目了。這兩天又全面的看了一下相關(guān)的基礎(chǔ)知識(學(xué)而時(shí)習(xí)之嘛),總結(jié)了25個(gè)問題: 1.靜態(tài)變量和非靜態(tài)變量的區(qū)別? 以下是我做的一份參考答案(C# 語言范疇之內(nèi)),如果有不準(zhǔn)確、不全面的,歡迎各位朋友指正! 答: 靜態(tài)變量: 靜態(tài)變量使用 static 修飾符進(jìn)行聲明 在所屬類被裝載時(shí)創(chuàng)建 通過類進(jìn)行訪問 所屬類的所有實(shí)例的同一靜態(tài)變量都是同一個(gè)值 非靜態(tài)變量: 不帶有 static 修飾符聲明的變量稱做非靜態(tài)變量 在類被實(shí)例化時(shí)創(chuàng)建 通過對象進(jìn)行訪問 同一個(gè)類的不同實(shí)例的同一非靜態(tài)變量可以是不同的值 示例: using System;
using System.Collections.Generic;
using System.Text;
namespace Example01
{ class Program
{ class Class1
{ public static String staticStr = "Class"; public String notstaticStr = "Obj"; } static void Main(string[] args) { //靜態(tài)變量通過類進(jìn)行訪問,該類所有實(shí)例的同一靜態(tài)變量都是同一個(gè)值
Console.WriteLine("Class1‘s staticStr: {0}", Class1.staticStr);
Class1 tmpObj1 = new Class1();
tmpObj1.notstaticStr = "tmpObj1";
Class1 tmpObj2 = new Class1();
tmpObj2.notstaticStr = "tmpObj2";
//非靜態(tài)變量通過對象進(jìn)行訪問,不同對象的同一非靜態(tài)變量可以有不同的值
Console.WriteLine("tmpObj1‘s notstaticStr: {0}", tmpObj1.notstaticStr);
Console.WriteLine("tmpObj2‘s notstaticStr: {0}", tmpObj2.notstaticStr);
Console.ReadLine(); } } } 結(jié)果:
答: const 用 const 修飾符聲明的成員叫常量,是在編譯期初始化并嵌入到客戶端程序 static readonly 用 static readonly 修飾符聲明的成員依然是變量,只不過具有和常量類似的使用方法:通過類進(jìn)行訪問、初始化后不可以修改。但與常量不同的是這種變量是在運(yùn)行期初始化 示例: 測試類: using System;
using System.Collections.Generic;
using System.Text;
namespace Example02Lib
{ public class Class1 { public const String strConst = "Const"; public static readonly String strStaticReadonly = "StaticReadonly"; //public const String strConst = "Const Changed";
//public static readonly String strStaticReadonly = "StaticReadonly Changed";
} } 客戶端代碼: using System;
using System.Collections.Generic;
using System.Text;
using Example02Lib;
namespace Example02
{ class Program
{ static void Main(string[] args) { //修改Example02中Class1的strConst初始值后,只編譯Example02Lib項(xiàng)目
//然后到資源管理器里把新編譯的Example02Lib.dll拷貝Example02.exe所在的目錄,執(zhí)行Example02.exe
//切不可在IDE里直接調(diào)試運(yùn)行因?yàn)檫@會重新編譯整個(gè)解決方案?。?/span>
//可以看到strConst的輸出沒有改變,而strStaticReadonly的輸出已經(jīng)改變
//表明Const變量是在編譯期初始化并嵌入到客戶端程序,而StaticReadonly是在運(yùn)行時(shí)初始化的
Console.WriteLine("strConst : {0}", Class1.strConst);
Console.WriteLine("strStaticReadonly : {0}", Class1.strStaticReadonly);
Console.ReadLine(); } } } 結(jié)果: 修改后的示例: 測試類: using System;
using System.Collections.Generic;
using System.Text;
namespace Example02Lib
{ public class Class1 { //public const String strConst = "Const";
//public static readonly String strStaticReadonly = "StaticReadonly";
public const String strConst = "Const Changed"; public static readonly String strStaticReadonly = "StaticReadonly Changed"; } } 結(jié)果 strConst : Const
答: extern 修飾符用于聲明由程序集外部實(shí)現(xiàn)的成員函數(shù) 經(jīng)常用于系統(tǒng)API函數(shù)的調(diào)用(通過 DllImport )。注意,和DllImport一起使用時(shí)要加上 static 修飾符 也可以用于對于同一程序集不同版本組件的調(diào)用(用 extern 聲明別名) 不能與 abstract 修飾符同時(shí)使用 示例: using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace Example03
{ class Program
{ //注意DllImport是一個(gè)Attribute Property,在System.Runtime.InteropServices命名空間中定義
//extern與DllImport一起使用時(shí)必須再加上一個(gè)static修飾符
[DllImport("User32.dll")]
public static extern int MessageBox(int Handle, string Message, string Caption, int Type); static int Main() { string myString;
Console.Write("Enter your message: ");
myString = Console.ReadLine(); return MessageBox(0, myString, "My Message Box", 0); } } }
答: abstract 修飾符可以用于類、方法、屬性、事件和索引指示器(indexer),表示其為抽象成員 abstract 不可以和 static 、virtual 、override 一起使用 聲明為 abstract 成員可以不包括實(shí)現(xiàn)代碼,但只有類中還有未實(shí)現(xiàn)的抽象成員,該類就不可以被實(shí)例化,通常用于強(qiáng)制繼承類必須實(shí)現(xiàn)某一成員 示例: using System;
using System.Collections.Generic;
using System.Text;
namespace Example04
{ #region 基類,抽象類
public abstract class BaseClass { //抽象屬性,同時(shí)具有g(shù)et和set訪問器表示繼承類必須將該屬性實(shí)現(xiàn)為可讀寫
public abstract String Attribute { get; set; } //抽象方法,傳入一個(gè)字符串參數(shù)無返回值
public abstract void Function(String value); //抽象事件,類型為系統(tǒng)預(yù)定義的代理(delegate):EventHandler
public abstract event EventHandler Event; //抽象索引指示器,只具有g(shù)et訪問器表示繼承類必須將該索引指示器實(shí)現(xiàn)為只讀
public abstract Char this[int Index] { get; } } #endregion
#region 繼承類
public class DeriveClass : BaseClass { private String attribute;
public override String Attribute { get { return attribute;
} set { attribute = value;
} } public override void Function(String value) { attribute = value;
if (Event != null) { Event(this, new EventArgs()); } } public override event EventHandler Event; public override Char this[int Index] { get { return attribute[Index];
} } } #endregion
class Program
{ static void OnFunction(object sender, EventArgs e) { for (int i = 0; i < ((DeriveClass)sender).Attribute.Length; i++) { Console.WriteLine(((DeriveClass)sender)[i]); } } static void Main(string[] args) { DeriveClass tmpObj = new DeriveClass();
tmpObj.Attribute = "1234567";
Console.WriteLine(tmpObj.Attribute); //將靜態(tài)函數(shù)OnFunction與tmpObj對象的Event事件進(jìn)行關(guān)聯(lián)
tmpObj.Event += new EventHandler(OnFunction);
tmpObj.Function("7654321");
Console.ReadLine(); } } } 結(jié)果:
答: internal 修飾符可以用于類型或成員,使用該修飾符聲明的類型或成員只能在同一程集內(nèi)訪問 接口的成員不能使用 internal 修飾符 示例 Example05Lib 項(xiàng)目的 Class1 using System;
using System.Collections.Generic;
using System.Text;
namespace Example05Lib
{ public class Class1 { internal String strInternal = null; public String strPublic;
} } 結(jié)果 Example05 項(xiàng)目的 Program 類無法訪問到 Class1 的 strInternal 成員
答: sealed 修飾符表示密封 用于類時(shí),表示該類不能再被繼承,不能和 abstract 同時(shí)使用,因?yàn)檫@兩個(gè)修飾符在含義上互相排斥 用于方法和屬性時(shí),表示該方法或?qū)傩圆荒茉俦焕^承,必須和 override 關(guān)鍵字一起使用,因?yàn)槭褂?sealed 修飾符的方法或?qū)傩钥隙ㄊ腔愔邢鄳?yīng)的虛成員 通常用于實(shí)現(xiàn)第三方類庫時(shí)不想被客戶端繼承,或用于沒有必要再繼承的類以防止濫用繼承造成層次結(jié)構(gòu)體系混亂 恰當(dāng)?shù)睦?sealed 修飾符也可以提高一定的運(yùn)行效率,因?yàn)椴挥每紤]繼承類會重寫該成員 示例: using System;
using System.Collections.Generic;
using System.Text;
namespace Example06
{ class Program
{ class A
{ public virtual void F() { Console.WriteLine("A.F");
} public virtual void G() { Console.WriteLine("A.G");
} } class B : A
{ public sealed override void F() { Console.WriteLine("B.F");
} public override void G() { Console.WriteLine("B.G");
} } class C : B
{ public override void G() { Console.WriteLine("C.G");
} } static void Main(string[] args) { new A().F();
new A().G();
new B().F();
new B().G();
new C().F();
new C().G();
Console.ReadLine(); } } } 結(jié)果: 由于類 B 中對 F 方法進(jìn)行了密封, 類 C 在繼承類 B 時(shí)只能重寫一個(gè)函數(shù),如圖所示: 控制臺輸出結(jié)果,類 C 的方法 F 只能是輸出 類B 中對該方法的實(shí)現(xiàn): A.F
答: override 表示重寫,用于繼承類對基類中虛成員的實(shí)現(xiàn) override 表示重載,用于同一個(gè)類中同名方法不同參數(shù)(包括類型不同或個(gè)數(shù)不同)的實(shí)現(xiàn) 示例: using System;
using System.Collections.Generic;
using System.Text;
namespace Example07
{ class Program
{ class BaseClass
{ public virtual void F() { Console.WriteLine("BaseClass.F");
} } class DeriveClass : BaseClass
{ public override void F() { base.F();
Console.WriteLine("DeriveClass.F");
} public void Add(int Left, int Right) { Console.WriteLine("Add for Int: {0}", Left + Right);
} public void Add(double Left, double Right) { Console.WriteLine("Add for int: {0}", Left + Right);
} } static void Main(string[] args) { DeriveClass tmpObj = new DeriveClass();
tmpObj.F(); tmpObj.Add(1, 2); tmpObj.Add(1.1, 2.2); Console.ReadLine(); } } } 結(jié)果:
答: 實(shí)現(xiàn)索引指示器(indexer)的類可以象數(shù)組那樣使用其實(shí)例后的對象 示例: using System;
using System.Collections.Generic;
using System.Text;
namespace Example08
{ public class Point { private double x, y; public Point(double X, double Y) { x = X; y = Y; } //重寫ToString方法方便輸出
public override string ToString() { return String.Format("X: {0} , Y: {1}", x, y); } } public class Points { Point[] points; public Points(Point[] Points)
{ points = Points; } public int PointNumber { get { return points.Length;
} } //實(shí)現(xiàn)索引訪問器
public Point this[int Index] { get { return points[Index];
} } } class Program
{ static void Main(string[] args) { Point[] tmpPoints = new Point[10];
for (int i = 0; i < tmpPoints.Length; i++) { tmpPoints[i] = new Point(i, Math.Sin(i));
} Points tmpObj = new Points(tmpPoints);
for (int i = 0; i < tmpObj.PointNumber; i++) { Console.WriteLine(tmpObj[i]); } Console.ReadLine(); } } } 結(jié)果:
答: new 修飾符與 new 操作符是兩個(gè)概念 new 修飾符用于聲明類或類的成員,表示隱藏了基類中同名的成員。而new 操作符用于實(shí)例化一個(gè)類型 new 修飾符只能用于繼承類,一般用于彌補(bǔ)基類設(shè)計(jì)的不足 new 修飾符和 override 修飾符不可同時(shí)用在一個(gè)成員上,因?yàn)檫@兩個(gè)修飾符在含義上互相排斥 示例: using System;
using System.Collections.Generic;
using System.Text;
namespace Example09
{ class BaseClass
{ //基類設(shè)計(jì)者聲明了一個(gè)PI的公共變量,方便進(jìn)行運(yùn)算
public static double PI = 3.1415; } class DervieClass : BaseClass
{ //繼承類發(fā)現(xiàn)該變量的值不能滿足運(yùn)算精度,于是可以通過new修飾符顯示隱藏基類中的聲明
public new static double PI = 3.1415926; } class Program
{ static void Main(string[] args) { Console.WriteLine(BaseClass.PI); Console.WriteLine(DervieClass.PI); Console.ReadLine(); } } } 結(jié)果:
答: this 是一個(gè)保留字,僅限于構(gòu)造函數(shù)和方法成員中使用 在類的構(gòu)造函數(shù)中出現(xiàn)表示對正在構(gòu)造的對象本身的引用,在類的方法中出現(xiàn)表示對調(diào)用該方法的對象的引用,在結(jié)構(gòu)的構(gòu)造上函數(shù)中出現(xiàn)表示對正在構(gòu)造的結(jié)構(gòu)的引用,在結(jié)構(gòu)的方法中出現(xiàn)表示對調(diào)用該方法的結(jié)果的引用 this 保留字不能用于靜態(tài)成員的實(shí)現(xiàn)里,因?yàn)檫@時(shí)對象或結(jié)構(gòu)并未實(shí)例化 在 C# 系統(tǒng)中,this 實(shí)際上是一個(gè)常量,所以不能使用 this++ 這樣的運(yùn)算 this 保留字一般用于限定同名的隱藏成員、將對象本身做為參數(shù)、聲明索引訪問器、判斷傳入?yún)?shù)的對象是否為本身 示例: using System;
using System.Collections.Generic;
using System.Text;
namespace Example10
{ class Class1
{ private double c; private string value; public double C { get { return c;
} } public Class1(double c) { //限定同名的隱藏成員
this.c = c;
} public Class1(Class1 value) { //用對象本身實(shí)例化自己沒有意義
if (this != value) { c = value.C;
} } public override string ToString() { //將對象本身做為參數(shù)
return string.Format("{0} Celsius = {1} Fahrenheit", c, UnitTransClass.C2F(this)); } //由于好奇,在這做了一個(gè)效率測試,想看看到底哪種方式訪問成員變量更快,結(jié)論:區(qū)別不大。。。
public string Test1() { long vTickCount = Environment.TickCount;
for (int i = 0; i < 10000000; i++) this.value = i.ToString(); return string.Format("Have this.: {0} MSEL", Environment.TickCount - vTickCount); } public string Test2() { long vTickCount = Environment.TickCount;
for (int i = 0; i < 10000000; i++) value = i.ToString();
return string.Format("Don‘t have this.: {0} MSEL", Environment.TickCount - vTickCount); } } class UnitTransClass
{ public static double C2F(Class1 value) { //攝氏到華氏的轉(zhuǎn)換公式
return 1.8 * value.C + 32; } } class Program
{ static void Main(string[] args) { Class1 tmpObj = new Class1(37.5);
Console.WriteLine(tmpObj); Console.WriteLine(tmpObj.Test1()); Console.WriteLine(tmpObj.Test2()); Console.ReadLine(); } } } 結(jié)果:
答: 可以,但需使用 new 修飾符顯式聲明,表示隱藏了基類中該函數(shù)的實(shí)現(xiàn) 示例: class BaseClass
{ public virtual void F() { Console.WriteLine("BaseClass.F");
} } abstract class DeriveClass : BaseClass { public new abstract void F(); }
答: 可以,基類中的虛函數(shù)將隱式的轉(zhuǎn)化為非虛函數(shù),但密封類本身不能再增加新的虛函數(shù) 示例: class BaseClass
{ public virtual void F() { Console.WriteLine("BaseClass.F");
} } sealed class DeriveClass : BaseClass { //基類中的虛函數(shù)F被隱式的轉(zhuǎn)化為非虛函數(shù)
//密封類中不能再聲明新的虛函數(shù)G
//public virtual void G()
//{
// Console.WriteLine("DeriveClass.G");
//}
}
答: 如果基類中的虛屬性只有一個(gè)屬性訪問器,那么繼承類重寫該屬性后也應(yīng)只有一個(gè)。如果基類中有 get 和 set 兩個(gè)屬性訪問器,那么繼承類中可以只有一個(gè)也可以同時(shí)有兩個(gè)屬性訪問器
答: abstract 修飾符不可以和 static、virtual 和 override 修飾符一起使用
答: 接口可以包含屬性、方法、索引指示器和事件,但不能包含常量、域、操作符、構(gòu)造函數(shù)和析構(gòu)函數(shù),而且也不能包含任何靜態(tài)成員
16.類和結(jié)構(gòu)的區(qū)別? 答: 類是引用類型在堆上分配,類的實(shí)例進(jìn)行賦值只是復(fù)制了引用,都指向同一段實(shí)際對象分配的內(nèi)存 類有構(gòu)造和析構(gòu)函數(shù) 類可以繼承和被繼承 結(jié)構(gòu): 結(jié)構(gòu)是值類型在棧上分配(雖然棧的訪問速度比較堆要快,但棧的資源有限放),結(jié)構(gòu)的賦值將分配產(chǎn)生一個(gè)新的對象。 結(jié)構(gòu)沒有構(gòu)造函數(shù),但可以添加。結(jié)構(gòu)沒有析構(gòu)函數(shù) 結(jié)構(gòu)不可以繼承自另一個(gè)結(jié)構(gòu)或被繼承,但和類一樣可以繼承自接口
示例: 根據(jù)以上比較,我們可以得出一些輕量級的對象最好使用結(jié)構(gòu),但數(shù)據(jù)量大或有復(fù)雜處理邏輯對象最好使用類。 如:Geoemtry(GIS 里的一個(gè)概論,在 OGC 標(biāo)準(zhǔn)里有定義) 最好使用類,而 Geometry 中點(diǎn)的成員最好使用結(jié)構(gòu) using System;
using System.Collections.Generic;
using System.Text;
namespace Example16
{ interface IPoint
{ double X
{ get; set; } double Y
{ get; set; } double Z
{ get; set; } } //結(jié)構(gòu)也可以從接口繼承
struct Point: IPoint
{ private double x, y, z; //結(jié)構(gòu)也可以增加構(gòu)造函數(shù)
public Point(double X, double Y, double Z) { this.x = X;
this.y = Y;
this.z = Z;
} public double X { get { return x; }
set { x = value; }
} public double Y { get { return x; }
set { x = value; }
} public double Z { get { return x; }
set { x = value; }
} } //在此簡化了點(diǎn)狀Geometry的設(shè)計(jì),實(shí)際產(chǎn)品中還包含Project(坐標(biāo)變換)等復(fù)雜操作
class PointGeometry
{ private Point value; public PointGeometry(double X, double Y, double Z) { value = new Point(X, Y, Z); } public PointGeometry(Point value) { //結(jié)構(gòu)的賦值將分配新的內(nèi)存
this.value = value; } public double X { get { return value.X; } set { this.value.X = value; } } public double Y { get { return value.Y; } set { this.value.Y = value; } } public double Z { get { return value.Z; } set { this.value.Z = value; } } public static PointGeometry operator +(PointGeometry Left, PointGeometry Rigth) { return new PointGeometry(Left.X + Rigth.X, Left.Y + Rigth.Y, Left.Z + Rigth.Z); } public override string ToString() { return string.Format("X: {0}, Y: {1}, Z: {2}", value.X, value.Y, value.Z); } } class Program
{ static void Main(string[] args) { Point tmpPoint = new Point(1, 2, 3);
PointGeometry tmpPG1 = new PointGeometry(tmpPoint);
PointGeometry tmpPG2 = new PointGeometry(tmpPoint);
tmpPG2.X = 4; tmpPG2.Y = 5; tmpPG2.Z = 6; //由于結(jié)構(gòu)是值類型,tmpPG1 和 tmpPG2 的坐標(biāo)并不一樣
Console.WriteLine(tmpPG1); Console.WriteLine(tmpPG2); //由于類是引用類型,對tmpPG1坐標(biāo)修改后影響到了tmpPG3
PointGeometry tmpPG3 = tmpPG1; tmpPG1.X = 7; tmpPG1.Y = 8; tmpPG1.Z = 9; Console.WriteLine(tmpPG1); Console.WriteLine(tmpPG3); Console.ReadLine(); } } } 結(jié)果:
答: C# 中的接口與類不同,可以使用多繼承,即一個(gè)子接口可以有多個(gè)父接口。但如果兩個(gè)父成員具有同名的成員,就產(chǎn)生了二義性(這也正是 C# 中類取消了多繼承的原因之一),這時(shí)在實(shí)現(xiàn)時(shí)最好使用顯式的聲明 示例: using System;
using System.Collections.Generic;
using System.Text;
namespace Example17
{ class Program
{ //一個(gè)完整的接口聲明示例
interface IExample
{ //屬性
string P
{ get; set; } //方法
string F(int Value); //事件
event EventHandler E;
//索引指示器
string this[int Index] { get; set; } } interface IA
{ int Count { get; set;}
} interface IB
{ int Count();
} //IC接口從IA和IB多重繼承
interface IC : IA, IB
{ } class C : IC
{ private int count = 100; //顯式聲明實(shí)現(xiàn)IA接口中的Count屬性
int IA.Count
{ get { return 100; }
set { count = value; }
} //顯式聲明實(shí)現(xiàn)IB接口中的Count方法
int IB.Count()
{ return count * count;
} } static void Main(string[] args) { C tmpObj = new C();
//調(diào)用時(shí)也要顯式轉(zhuǎn)換
Console.WriteLine("Count property: {0}", ((IA)tmpObj).Count);
Console.WriteLine("Count function: {0}", ((IB)tmpObj).Count());
Console.ReadLine(); } } } 結(jié)果:
答: 抽象類(abstract class)可以包含功能定義和實(shí)現(xiàn),接口(interface)只能包含功能定義 抽象類是從一系列相關(guān)對象中抽象出來的概念, 因此反映的是事物的內(nèi)部共性;接口是為了滿足外部調(diào)用而定義的一個(gè)功能約定, 因此反映的是事物的外部特性 分析對象,提煉內(nèi)部共性形成抽象類,用以表示對象本質(zhì),即“是什么” 為外部提供調(diào)用或功能需要擴(kuò)充時(shí)優(yōu)先使用接口
答: 通過別名指示符我們可以為某個(gè)類型起一個(gè)別名 主要用于解決兩個(gè)命名空間內(nèi)有同名類型的沖突或避免使用冗余的命名空間 別名指示符只在一個(gè)單元文件內(nèi)起作用 示例: Class1.cs: using System;
using System.Collections.Generic;
using System.Text;
namespace com.nblogs.reonlyrun.CSharp26QExample.Example19.Lib01
{ class Class1
{ public override string ToString() { return "com.nblogs.reonlyrun.CSharp26QExample.Example19.Lib01‘s Class1"; } } } Class2.cs using System;
using System.Collections.Generic;
using System.Text;
namespace com.nblogs.reonlyrun.CSharp26QExample.Example19.Lib02
{ class Class1
{ public override string ToString() { return "com.nblogs.reonlyrun.CSharp26QExample.Example19.Lib02‘s Class1"; } } } 主單元(Program.cs): using System;
using System.Collections.Generic;
using System.Text;
//使用別名指示符解決同名類型的沖突
using Lib01Class1 = com.nblogs.reonlyrun.CSharp26QExample.Example19.Lib01.Class1;
using Lib02Class2 = com.nblogs.reonlyrun.CSharp26QExample.Example19.Lib02.Class1;
namespace Example19
{ class Program
{ static void Main(string[] args) { Lib01Class1 tmpObj1 = new Lib01Class1();
Lib02Class2 tmpObj2 = new Lib02Class2();
Console.WriteLine(tmpObj1); Console.WriteLine(tmpObj2); Console.ReadLine(); } } } 結(jié)果:
20.如何釋放非托管資源? 答: .NET 平臺在內(nèi)存管理方面提供了GC(Garbage Collection),負(fù)責(zé)自動釋放托管資源和內(nèi)存回收的工作,但它無法對非托管資源進(jìn)行釋放,這時(shí)我們必須自己提供方法來釋放對象內(nèi)分配的非托管資源,比如你在對象的實(shí)現(xiàn)代碼中使用了一個(gè)COM對象 最簡單的辦法,可以通過實(shí)現(xiàn)protected void Finalize()(析構(gòu)函數(shù)會在編譯時(shí)變成這個(gè)東東)來釋放非托管資源,因?yàn)镚C在釋放對象時(shí)會檢查該對象是否實(shí)現(xiàn)了 Finalize() 方法,如果是則調(diào)用它。但,據(jù)說這樣會降低效率。。。 有一種更好的,那就是通過實(shí)現(xiàn)一個(gè)接口顯式的提供給客戶調(diào)用端手工釋放對象的方法,而不是傻傻的等著GC來釋放我們的對象(何況效率又那么低) System 命名空間內(nèi)有一個(gè) IDisposable 接口,拿來做這事非常合適,就省得我們自己再聲明一個(gè)接口了 另外補(bǔ)充一句,這種實(shí)現(xiàn)并不一定要使用了非托管資源后才用,如果你設(shè)計(jì)的類會在運(yùn)行時(shí)有大些的實(shí)例(象 GIS 中的Geometry),為了優(yōu)化程序性能,你也可以通過實(shí)現(xiàn)該接口讓客戶調(diào)用端在確認(rèn)不需要這些對象時(shí)手工釋放它們 示例: using System;
using System.Collections.Generic;
using System.Text;
namespace Example20
{ class Program
{ class Class1 : IDisposable
{ //析構(gòu)函數(shù),編譯后變成 protected void Finalize(),GC會在回收對象前會調(diào)用調(diào)用該方法
~Class1() { Dispose(false);
} //通過實(shí)現(xiàn)該接口,客戶可以顯式地釋放對象,而不需要等待GC來釋放資源,據(jù)說那樣會降低效率
void IDisposable.Dispose()
{ Dispose(true);
} //將釋放非托管資源設(shè)計(jì)成一個(gè)虛函數(shù),提供在繼承類中釋放基類的資源的能力
protected virtual void ReleaseUnmanageResources() { //Do something...
} //私有函數(shù)用以釋放非托管資源
private void Dispose(bool disposing) { ReleaseUnmanageResources(); //為true時(shí)表示是客戶顯式調(diào)用了釋放函數(shù),需通知GC不要再調(diào)用對象的Finalize方法
//為false時(shí)肯定是GC調(diào)用了對象的Finalize方法,所以沒有必要再告訴GC你不要調(diào)用我的Finalize方法啦
if (disposing)
{ GC.SuppressFinalize(this);
} } } static void Main(string[] args) { //tmpObj1沒有手工釋放資源,就等著GC來慢慢的釋放它吧
Class1 tmpObj1 = new Class1();
//tmpObj2調(diào)用了Dispose方法,傳說比等著GC來釋放它效率要調(diào)一些
//個(gè)人認(rèn)為是因?yàn)橐饌€(gè)對象的查看其元數(shù)據(jù),以確認(rèn)是否實(shí)現(xiàn)了Dispose方法吧
//當(dāng)然最重要的是我們可以自己確定釋放的時(shí)間以節(jié)省內(nèi)存,優(yōu)化程序運(yùn)行效率
Class1 tmpObj2 = new Class1();
((IDisposable)tmpObj2).Dispose(); } } }
答: 在受控代碼與非受控代碼進(jìn)行交互時(shí)會產(chǎn)生一個(gè)事務(wù)(transition) ,這通常發(fā)生在使用平臺調(diào)用服務(wù)(Platform Invocation Services),即P/Invoke 如調(diào)用系統(tǒng)的 API 或與 COM 對象打交道,通過 System.Runtime.InteropServices 命名空間 雖然使用 Interop 非常方便,但據(jù)估計(jì)每次調(diào)用事務(wù)都要執(zhí)行 10 到 40 條指令,算起來開銷也不少,所以我們要盡量少調(diào)用事務(wù) 如果非用不可,建議本著一次調(diào)用執(zhí)行多個(gè)動作,而不是多次調(diào)用每次只執(zhí)行少量動作的原則
22.StringBuilder 和 String 的區(qū)別? 答: String 雖然是一個(gè)引用類型,但在賦值操作時(shí)會產(chǎn)生一個(gè)新的對象,而 StringBuilder 則不會 所以在大量字符串拼接或頻繁對某一字符串進(jìn)行操作時(shí)最好使用 StringBuilder,不要使用 String 示例: using System;
using System.Collections.Generic;
using System.Text;
namespace Example22
{ class Program
{ static void Main(string[] args) { const int cycle = 100000; long vTickCount = Environment.TickCount;
String str = null;
for (int i = 0; i < cycle; i++) str += i.ToString(); Console.WriteLine("String: {0} MSEL", Environment.TickCount - vTickCount);
vTickCount = Environment.TickCount; //看到這個(gè)變量名我就生氣,奇怪為什么大家都使它呢? :)
StringBuilder sb = new StringBuilder();
for (int i = 0; i < cycle; i++) sb.Append(i); Console.WriteLine("StringBuilder: {0} MSEL", Environment.TickCount - vTickCount);
Console.ReadLine(); } } } 結(jié)果: 23.explicit 和 implicit 的含義? 答: explicit 和 implicit 屬于轉(zhuǎn)換運(yùn)算符,如用這兩者可以讓我們自定義的類型支持相互交換 explicti 表示顯式轉(zhuǎn)換,如從 A -> B 必須進(jìn)行強(qiáng)制類型轉(zhuǎn)換(B = (B)A) implicit 表示隱式轉(zhuǎn)換,如從 B -> A 只需直接賦值(A = B) 隱式轉(zhuǎn)換可以讓我們的代碼看上去更漂亮、更簡潔易懂,所以最好多使用 implicit 運(yùn)算符。不過!如果對象本身在轉(zhuǎn)換時(shí)會損失一些信息(如精度),那么我們只能使用 explicit 運(yùn)算符,以便在編譯期就能警告客戶調(diào)用端 示例: using System;
using System.Collections.Generic;
using System.Text;
namespace Example23
{ class Program
{ //本例靈感來源于大話西游經(jīng)典臺詞“神仙?妖怪?”--主要是我實(shí)在想不出什么好例子了
class Immortal
{ public string name; public Immortal(string Name) { name = Name; } public static implicit operator Monster(Immortal value) { return new Monster(value.name + ":神仙變妖怪?偷偷下凡即可。。。"); } } class Monster
{ public string name; public Monster(string Name) { name = Name; } public static explicit operator Immortal(Monster value) { return new Immortal(value.name + ":妖怪想當(dāng)神仙?再去修煉五百年!"); } } static void Main(string[] args) { Immortal tmpImmortal = new Immortal("紫霞仙子"); //隱式轉(zhuǎn)換
Monster tmpObj1 = tmpImmortal; Console.WriteLine(tmpObj1.name); Monster tmpMonster = new Monster("孫悟空"); //顯式轉(zhuǎn)換
Immortal tmpObj2 = (Immortal)tmpMonster; Console.WriteLine(tmpObj2.name); Console.ReadLine(); } } } 結(jié)果: 答: params 關(guān)鍵字在方法成員的參數(shù)列表中使用,為該方法提供了參數(shù)個(gè)數(shù)可變的能力 它在只能出現(xiàn)一次并且不能在其后再有參數(shù)定義,之前可以 示例: using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{ class App
{ //第一個(gè)參數(shù)必須是整型,但后面的參數(shù)個(gè)數(shù)是可變的。
//而且由于定的是object數(shù)組,所有的數(shù)據(jù)類型都可以做為參數(shù)傳入
public static void UseParams(int id, params object[] list) { Console.WriteLine(id); for (int i = 0; i < list.Length; i++) { Console.WriteLine(list[i]); } } static void Main() { //可變參數(shù)部分傳入了三個(gè)參數(shù),都是字符串類型
UseParams(1, "a", "b", "c"); //可變參數(shù)部分傳入了四個(gè)參數(shù),分別為字符串、整數(shù)、浮點(diǎn)數(shù)和雙精度浮點(diǎn)數(shù)數(shù)組
UseParams(2, "d", 100, 33.33, new double[] { 1.1, 2.2 }); Console.ReadLine(); } } } 結(jié)果:
答: 反射,Reflection,通過它我們可以在運(yùn)行時(shí)獲得各種信息,如程序集、模塊、類型、字段、屬性、方法和事件 通過對類型動態(tài)實(shí)例化后,還可以對其執(zhí)行操作 一般用于插件式框架程序和設(shè)計(jì)模式的實(shí)現(xiàn),當(dāng)然反射是一種手段可以充分發(fā)揮其能量來完成你想做的任何事情(前面好象見過一位高人用反射調(diào)用一個(gè)官方類庫中未說明的函數(shù)。。。) 示例: using System;
using System.Collections.Generic;
using System.Text;
namespace Example25Lib
{ public class Class1 { private string name; private int age; //如果顯式的聲明了無參數(shù)構(gòu)造函數(shù),客戶端只需要用程序集的CreateInstance即可實(shí)例化該類
//在此特意不實(shí)現(xiàn),以便在客戶調(diào)用端體現(xiàn)構(gòu)造函數(shù)的反射實(shí)現(xiàn)
//public Class1()
//{
//}
public Class1(string Name, int Age) { name = Name; age = Age; } public void ChangeName(string NewName) { name = NewName; } public void ChangeAge(int NewAge) { age = NewAge; } public override string ToString() { return string.Format("Name: {0}, Age: {1}", name, age); } } } 反射實(shí)例化對象并調(diào)用其方法,屬性和事件的反射調(diào)用略去 using System;
using System.Collections.Generic;
using System.Text;
//注意添加該反射的命名空間
using System.Reflection;
namespace Example25
{ class Program
{ static void Main(string[] args) { //加載程序集
Assembly tmpAss = Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + "Example25Lib.dll");
//遍歷程序集內(nèi)所有的類型,并實(shí)例化
Type[] tmpTypes = tmpAss.GetTypes(); foreach (Type tmpType in tmpTypes) { //獲取第一個(gè)類型的構(gòu)造函數(shù)信息
ConstructorInfo[] tmpConsInfos = tmpType.GetConstructors(); foreach (ConstructorInfo tmpConsInfo in tmpConsInfos) { //為構(gòu)造函數(shù)生成調(diào)用的參數(shù)集合
ParameterInfo[] tmpParamInfos = tmpConsInfo.GetParameters(); object[] tmpParams = new object[tmpParamInfos.Length]; for (int i = 0; i < tmpParamInfos.Length; i++) { tmpParams[i] = tmpAss.CreateInstance(tmpParamInfos[i].ParameterType.FullName); if (tmpParamInfos[i].ParameterType.FullName == "System.String") { tmpParams[i] = "Clark";
} } //實(shí)例化對象
object tmpObj = tmpConsInfo.Invoke(tmpParams);
Console.WriteLine(tmpObj); //獲取所有方法并執(zhí)行
foreach (MethodInfo tmpMethod in tmpType.GetMethods()) { //為方法的調(diào)用創(chuàng)建參數(shù)集合
tmpParamInfos = tmpMethod.GetParameters(); tmpParams = new object[tmpParamInfos.Length]; for (int i = 0; i < tmpParamInfos.Length; i++) { tmpParams[i] = tmpAss.CreateInstance(tmpParamInfos[i].ParameterType.FullName); if (tmpParamInfos[i].ParameterType.FullName == "System.String") { tmpParams[i] = "Clark Zheng";
} if (tmpParamInfos[i].ParameterType.FullName == "System.Int32") { tmpParams[i] = 27; } } tmpMethod.Invoke(tmpObj, tmpParams); } //調(diào)用完方法后再次打印對象,比較結(jié)果
Console.WriteLine(tmpObj); } } Console.ReadLine(); } } } 結(jié)果:
示例下載:http://www.cnblogs.com/Files/reonlyrun/CSharp25QExample.rar |
|