C#基礎(chǔ)概念二十五問(wèn) 21-25
更新時(shí)間:2007年04月09日 00:00:00 作者:
21.P/Invoke是什么?
答:
在受控代碼與非受控代碼進(jìn)行交互時(shí)會(huì)產(chǎn)生一個(gè)事務(wù)(transition) ,這通常發(fā)生在使用平臺(tái)調(diào)用服務(wù)(Platform Invocation Services),即P/Invoke
如調(diào)用系統(tǒng)的 API 或與 COM 對(duì)象打交道,通過(guò) System.Runtime.InteropServices 命名空間
雖然使用 Interop 非常方便,但據(jù)估計(jì)每次調(diào)用事務(wù)都要執(zhí)行 10 到 40 條指令,算起來(lái)開(kāi)銷也不少,所以我們要盡量少調(diào)用事務(wù)
如果非用不可,建議本著一次調(diào)用執(zhí)行多個(gè)動(dòng)作,而不是多次調(diào)用每次只執(zhí)行少量動(dòng)作的原則
22.StringBuilder 和 String 的區(qū)別?
答:
String 在進(jìn)行運(yùn)算時(shí)(如賦值、拼接等)會(huì)產(chǎn)生一個(gè)新的實(shí)例,而 StringBuilder 則不會(huì)。所以在大量字符串拼接或頻繁對(duì)某一字符串進(jìn)行操作時(shí)最好使用 StringBuilder,不要使用 String
另外,對(duì)于 String 我們不得不多說(shuō)幾句:
1.它是引用類型,在堆上分配內(nèi)存
2.運(yùn)算時(shí)會(huì)產(chǎn)生一個(gè)新的實(shí)例
3.String 對(duì)象一旦生成不可改變(Immutable)
3.定義相等運(yùn)算符(== 和 !=)是為了比較 String 對(duì)象(而不是引用)的值
示例:
using System;
using System.Collections.Generic;
using System.Text;
namespace Example22
{
class Program
{
static void Main(string[] args)
{
const int cycle = 10000;
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);
string tmpStr1 = "A";
string tmpStr2 = tmpStr1;
Console.WriteLine(tmpStr1);
Console.WriteLine(tmpStr2);
//注意后面的輸出結(jié)果,tmpStr1的值改變并未影響到tmpStr2的值
tmpStr1 = "B";
Console.WriteLine(tmpStr1);
Console.WriteLine(tmpStr2);
Console.ReadLine();
}
}
}
結(jié)果:
String: 375 MSEL
StringBuilder: 16 MSEL
A
A
A
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)換可以讓我們的代碼看上去更漂亮、更簡(jiǎn)潔易懂,所以最好多使用 implicit 運(yùn)算符。不過(guò)!如果對(duì)象本身在轉(zhuǎn)換時(shí)會(huì)損失一些信息(如精度),那么我們只能使用 explicit 運(yùn)算符,以便在編譯期就能警告客戶調(diào)用端
示例:
using System;
using System.Collections.Generic;
using System.Text;
namespace Example23
{
class Program
{
//本例靈感來(lái)源于大話西游經(jīng)典臺(tái)詞“神仙?妖怪?”--主要是我實(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
c
2
d
100
33.33
System.Double[]
25.什么是反射?
答:
反射,Reflection,通過(guò)它我們可以在運(yùn)行時(shí)獲得各種信息,如程序集、模塊、類型、字段、屬性、方法和事件
通過(guò)對(duì)類型動(dòng)態(tài)實(shí)例化后,還可以對(duì)其執(zhí)行操作
簡(jiǎn)單來(lái)說(shuō)就是用string可以在runtime為所欲為的東西,實(shí)際上就是一個(gè).net framework內(nèi)建的萬(wàn)能工廠
一般用于插件式框架程序和設(shè)計(jì)模式的實(shí)現(xiàn),當(dāng)然反射是一種手段可以充分發(fā)揮其能量來(lái)完成你想做的任何事情(前面好象見(jiàn)過(guò)一位高人用反射調(diào)用一個(gè)官方類庫(kù)中未說(shuō)明的函數(shù)。。。)
示例:
using System;
using System.Collections.Generic;
using System.Text;
namespace Example25Lib
{
public class Class1
{
private string name;
private int age;
//如果顯式的聲明了無(wú)參數(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í)例化對(duì)象并調(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í)例化對(duì)象
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)用完方法后再次打印對(duì)象,比較結(jié)果
Console.WriteLine(tmpObj);
}
}
Console.ReadLine();
}
}
}
結(jié)果:
Name: Clark, Age: 0
Name: Clark Zheng, Age: 27
來(lái)自:
http://www.cnblogs.com/reonlyrun/archive/2007/04/05/csharp_25_question.html
答:
在受控代碼與非受控代碼進(jìn)行交互時(shí)會(huì)產(chǎn)生一個(gè)事務(wù)(transition) ,這通常發(fā)生在使用平臺(tái)調(diào)用服務(wù)(Platform Invocation Services),即P/Invoke
如調(diào)用系統(tǒng)的 API 或與 COM 對(duì)象打交道,通過(guò) System.Runtime.InteropServices 命名空間
雖然使用 Interop 非常方便,但據(jù)估計(jì)每次調(diào)用事務(wù)都要執(zhí)行 10 到 40 條指令,算起來(lái)開(kāi)銷也不少,所以我們要盡量少調(diào)用事務(wù)
如果非用不可,建議本著一次調(diào)用執(zhí)行多個(gè)動(dòng)作,而不是多次調(diào)用每次只執(zhí)行少量動(dòng)作的原則
22.StringBuilder 和 String 的區(qū)別?
答:
String 在進(jìn)行運(yùn)算時(shí)(如賦值、拼接等)會(huì)產(chǎn)生一個(gè)新的實(shí)例,而 StringBuilder 則不會(huì)。所以在大量字符串拼接或頻繁對(duì)某一字符串進(jìn)行操作時(shí)最好使用 StringBuilder,不要使用 String
另外,對(duì)于 String 我們不得不多說(shuō)幾句:
1.它是引用類型,在堆上分配內(nèi)存
2.運(yùn)算時(shí)會(huì)產(chǎn)生一個(gè)新的實(shí)例
3.String 對(duì)象一旦生成不可改變(Immutable)
3.定義相等運(yùn)算符(== 和 !=)是為了比較 String 對(duì)象(而不是引用)的值
示例:
using System;
using System.Collections.Generic;
using System.Text;
namespace Example22
{
class Program
{
static void Main(string[] args)
{
const int cycle = 10000;
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);
string tmpStr1 = "A";
string tmpStr2 = tmpStr1;
Console.WriteLine(tmpStr1);
Console.WriteLine(tmpStr2);
//注意后面的輸出結(jié)果,tmpStr1的值改變并未影響到tmpStr2的值
tmpStr1 = "B";
Console.WriteLine(tmpStr1);
Console.WriteLine(tmpStr2);
Console.ReadLine();
}
}
}
結(jié)果:
String: 375 MSEL
StringBuilder: 16 MSEL
A
A
A
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)換可以讓我們的代碼看上去更漂亮、更簡(jiǎn)潔易懂,所以最好多使用 implicit 運(yùn)算符。不過(guò)!如果對(duì)象本身在轉(zhuǎn)換時(shí)會(huì)損失一些信息(如精度),那么我們只能使用 explicit 運(yùn)算符,以便在編譯期就能警告客戶調(diào)用端
示例:
using System;
using System.Collections.Generic;
using System.Text;
namespace Example23
{
class Program
{
//本例靈感來(lái)源于大話西游經(jīng)典臺(tái)詞“神仙?妖怪?”--主要是我實(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
c
2
d
100
33.33
System.Double[]
25.什么是反射?
答:
反射,Reflection,通過(guò)它我們可以在運(yùn)行時(shí)獲得各種信息,如程序集、模塊、類型、字段、屬性、方法和事件
通過(guò)對(duì)類型動(dòng)態(tài)實(shí)例化后,還可以對(duì)其執(zhí)行操作
簡(jiǎn)單來(lái)說(shuō)就是用string可以在runtime為所欲為的東西,實(shí)際上就是一個(gè).net framework內(nèi)建的萬(wàn)能工廠
一般用于插件式框架程序和設(shè)計(jì)模式的實(shí)現(xiàn),當(dāng)然反射是一種手段可以充分發(fā)揮其能量來(lái)完成你想做的任何事情(前面好象見(jiàn)過(guò)一位高人用反射調(diào)用一個(gè)官方類庫(kù)中未說(shuō)明的函數(shù)。。。)
示例:
using System;
using System.Collections.Generic;
using System.Text;
namespace Example25Lib
{
public class Class1
{
private string name;
private int age;
//如果顯式的聲明了無(wú)參數(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í)例化對(duì)象并調(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í)例化對(duì)象
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)用完方法后再次打印對(duì)象,比較結(jié)果
Console.WriteLine(tmpObj);
}
}
Console.ReadLine();
}
}
}
結(jié)果:
Name: Clark, Age: 0
Name: Clark Zheng, Age: 27
來(lái)自:
http://www.cnblogs.com/reonlyrun/archive/2007/04/05/csharp_25_question.html
相關(guān)文章
C#+無(wú)unsafe的非托管大數(shù)組示例詳解(large unmanaged array in c# without ‘u
這篇文章主要給大家介紹了關(guān)于C#+無(wú)unsafe的非托管大數(shù)組(large unmanaged array in c# without 'unsafe' keyword)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01C#模板方法模式(Template Method Pattern)實(shí)例教程
這篇文章主要介紹了C#模板方法模式(Template Method Pattern),以實(shí)例形式講述了C#抽象類模板方法的用法,具有很高的實(shí)用價(jià)值,需要的朋友可以參考下2014-09-09C# 修改文件的創(chuàng)建、修改和訪問(wèn)時(shí)間的示例
這篇文章主要介紹了C#實(shí)現(xiàn)修改文件的創(chuàng)建、修改和訪問(wèn)時(shí)間的示例,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下2021-04-04C#中WPF顏色對(duì)話框控件的實(shí)現(xiàn)
在 C# WPF開(kāi)發(fā)中顏色對(duì)話框控件(ColorDialog)用于對(duì)界面中的背景、文字…(擁有顏色屬性的所有控件)設(shè)置顏色,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03