一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

C#基礎(chǔ)概念二十五問

 goldbomb 2007-04-05

注:本文部份資料來自網(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ū)別?
2.const 和 static readonly 區(qū)別?
3.extern 是什么意思?
4.abstract 是什么意思?
5.internal 修飾符起什么作用?
6.sealed 修飾符是干什么的?
7.override 和 overload 的區(qū)別?
8.什么是索引指示器?
9.new 修飾符是起什么作用?
10.this 關(guān)鍵字的含義?
11.可以使用抽象函數(shù)重寫基類中的虛函數(shù)嗎?
12.密封類可以有虛函數(shù)嗎?
13.如果基類中的虛屬性只有一個(gè)屬性訪問器,那么繼承類重寫該屬性后可以有幾個(gè)屬性訪問器?如果基類中有 get 和 set 兩個(gè)呢?
14.abstract 可以和 virtual 一起使用嗎?可以和 override 一起使用嗎?
15.接口可以包含哪些成員?
16.類和結(jié)構(gòu)的區(qū)別?
17.接口的多繼承會帶來哪些問題?
18.抽象類和接口的區(qū)別?
19.別名指示符是什么?
20.如何釋放非托管資源?
21.P/Invoke是什么?
22.StringBuilder 和 String 的區(qū)別?
23.explicit 和 implicit 的含義?
24.params 有什么用?
25.什么是反射?

以下是我做的一份參考答案(C# 語言范疇之內(nèi)),如果有不準(zhǔn)確、不全面的,歡迎各位朋友指正!

 
1.靜態(tài)變量和非靜態(tài)變量的區(qū)別?

答:

靜態(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é)果:
Class1‘s staticStr: Class
tmpObj1‘s notstaticStr: tmpObj1
tmpObj2‘s notstaticStr: tmpObj2


2.const 和 static readonly 區(qū)別?

答:

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é)果:
strConst : Const
strStaticReadonly : StaticReadonly

修改后的示例:

測試類:

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
strStaticReadonly : StaticReadonly Changed


3.extern 是什么意思?

答:

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);
        }
    }
}

結(jié)果:


4.abstract 是什么意思?

答:

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é)果:
1234567
7
6
5
4
3
2
1


5.internal 修飾符起什么作用?

答:

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é)果
Example05Lib 項(xiàng)目的 Class2 類可以訪問到 Class1 的 strInternal 成員

Example05 項(xiàng)目的 Program 類無法訪問到 Class1 的 strInternal 成員


6.sealed 修飾符是干什么的?

答:

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 在繼承類 A 時(shí)可以重寫兩個(gè)虛函數(shù),如圖所示:

由于類 B 中對 F 方法進(jìn)行了密封, 類 C 在繼承類 B 時(shí)只能重寫一個(gè)函數(shù),如圖所示:

控制臺輸出結(jié)果,類 C 的方法 F 只能是輸出 類B 中對該方法的實(shí)現(xiàn):

A.F
A.G
B.F
B.G
B.F
C.G


7.override 和 overload 的區(qū)別?

答:

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é)果:
BaseClass.F
DeriveClass.F
Add for Int: 3
Add for int: 3.3


8.什么是索引指示器?

答:

實(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é)果:
X: 0 , Y: 0
X: 1 , Y: 0.841470984807897
X: 2 , Y: 0.909297426825682
X: 3 , Y: 0.141120008059867
X: 4 , Y: -0.756802495307928
X: 5 , Y: -0.958924274663138
X: 6 , Y: -0.279415498198926
X: 7 , Y: 0.656986598718789
X: 8 , Y: 0.989358246623382
X: 9 , Y: 0.412118485241757


9.new 修飾符是起什么作用?

答:

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é)果:
3.1415
3.1415926


10.this 關(guān)鍵字的含義?

答:

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é)果:
37.5 Celsius = 99.5 Fahrenheit
Have this.: 4375 MSEL
Don‘t have this.: 4406 MSEL


11.可以使用抽象函數(shù)重寫基類中的虛函數(shù)嗎?

答:

可以,但需使用 new 修飾符顯式聲明,表示隱藏了基類中該函數(shù)的實(shí)現(xiàn)

示例:

    class BaseClass
    {
        public virtual void F()
        {
            Console.WriteLine("BaseClass.F");
        }
    }
    abstract class  DeriveClass : BaseClass
    {
        public new abstract void F();
    }


12.密封類可以有虛函數(shù)嗎?

答:

可以,基類中的虛函數(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");
        //}
    }


13.如果基類中的虛屬性只有一個(gè)屬性訪問器,那么繼承類重寫該屬性后可以有幾個(gè)屬性訪問器?如果基類中有 get 和 set 兩個(gè)呢?

答:

如果基類中的虛屬性只有一個(gè)屬性訪問器,那么繼承類重寫該屬性后也應(yīng)只有一個(gè)。如果基類中有 get 和 set 兩個(gè)屬性訪問器,那么繼承類中可以只有一個(gè)也可以同時(shí)有兩個(gè)屬性訪問器


14.abstract 可以和 virtual 一起使用嗎?可以和 override 一起使用嗎?

答:

abstract 修飾符不可以和 static、virtual 和 override 修飾符一起使用


15.接口可以包含哪些成員?

答:

接口可以包含屬性、方法、索引指示器和事件,但不能包含常量、域、操作符、構(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é)果:
X: 1, Y: 2, Z: 3
X: 4, Y: 5, Z: 6
X: 7, Y: 8, Z: 9
X: 7, Y: 8, Z: 9


17.接口的多繼承會帶來哪些問題?

答:

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é)果:
Count property: 100
Count function: 10000


18.抽象類和接口的區(qū)別?

答:

抽象類(abstract class)可以包含功能定義和實(shí)現(xiàn),接口(interface)只能包含功能定義

抽象類是從一系列相關(guān)對象中抽象出來的概念, 因此反映的是事物的內(nèi)部共性;接口是為了滿足外部調(diào)用而定義的一個(gè)功能約定, 因此反映的是事物的外部特性

分析對象,提煉內(nèi)部共性形成抽象類,用以表示對象本質(zhì),即“是什么”

為外部提供調(diào)用或功能需要擴(kuò)充時(shí)優(yōu)先使用接口


19.別名指示符是什么?

答:

通過別名指示符我們可以為某個(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é)果:
com.nblogs.reonlyrun.CSharp26QExample.Example19.Lib01‘s Class1
com.nblogs.reonlyrun.CSharp26QExample.Example19.Lib02‘s Class1

 

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();
        }
    }
}


21.P/Invoke是什么?

答:

在受控代碼與非受控代碼進(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é)果:
String: 102047 MSEL
StringBuilder: 46 MSEL

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é)果:
紫霞仙子:神仙變妖怪?偷偷下凡即可。。。
孫悟空:妖怪想當(dāng)神仙?再去修煉五百年!

 
24.params 有什么用?

答:

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é)果:
1
a
b
c
2
d
100
33.33
System.Double[]


25.什么是反射?

答:

反射,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é)果:
Name: Clark, Age: 0
Name: Clark Zheng, Age: 27

 

示例下載:http://www.cnblogs.com/Files/reonlyrun/CSharp25QExample.rar

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    欧美成人一区二区三区在线| 日韩中文字幕人妻精品| 美女激情免费在线观看| 国产又色又爽又黄又免费| 欧美偷拍一区二区三区四区| 国产乱人伦精品一区二区三区四区 | 天堂网中文字幕在线视频| 国内尹人香蕉综合在线| 亚洲熟女一区二区三四区| 亚洲欧洲一区二区中文字幕| 亚洲欧美日本成人在线| 亚洲a码一区二区三区| 日韩人妻av中文字幕| 婷婷激情五月天丁香社区 | 亚洲欧美黑人一区二区| 国产精品第一香蕉视频| 亚洲精品欧美精品日韩精品| 亚洲欧美日韩中文字幕二欧美| 不卡一区二区高清视频| 在线观看免费视频你懂的 | 国产一级内片内射免费看| 亚洲深夜精品福利一区| 亚洲人妻av中文字幕| 欧美欧美日韩综合一区| 99久久国产精品免费| 国产中文字幕久久黄色片| 国产精品亚洲精品亚洲| 人人妻在人人看人人澡| 中国日韩一级黄色大片| 国产一区国产二区在线视频| 亚洲精品欧美精品日韩精品| 日本高清视频在线观看不卡| 亚洲妇女作爱一区二区三区| 九九热在线免费在线观看| 欧美成人免费夜夜黄啪啪| 不卡视频免费一区二区三区| 最新69国产精品视频| 婷婷一区二区三区四区| 欧美人妻一区二区三区| 一区二区三区欧美高清| 日韩欧美一区二区不卡视频|