1. 什么是局部類型?
C# 2.0 引入了局部類型的概念。局部類型允許我們將一個類、結(jié)構(gòu)或接口分成幾個部分,分別實現(xiàn)在幾個不同的.cs文件中。
局部類型適用于以下情況:
(1) 類型特別大,不宜放在一個文件中實現(xiàn)。
(2) 一個類型中的一部分代碼為自動化工具生成的代碼,不宜與我們自己編寫的代碼混合在一起。
(3) 需要多人合作編寫一個類。
局部類型是一個純語言層的編譯處理,不影響任何執(zhí)行機制——事實上C#編譯器在編譯的時候仍會將各個部分的局部類型合并成一個完整的類。
public partial class Program
{
static void Main(string[] args)
{
}
}
partial class Program
{
public void Test()
{
}
}
2. 局部類型的限制
(1) 局部類型只適用于類、接口、結(jié)構(gòu),不支持委托和枚舉。
(2) 同一個類型的各個部分必須都有修飾符 partial。
(3) 使用局部類型時,一個類型的各個部分必須位于相同的命名空間中。
(4) 一個類型的各個部分必須被同時編譯。
3. 局部類型的注意點
(1) 關(guān)鍵字partial是一個上下文關(guān)鍵字,只有和 class、struct、interface 放在一起時才有關(guān)鍵字的含義。因此partial的引入不會影響現(xiàn)有代碼中名稱為partial的變量。
(2) 局部類型的各個部分一般是分開放在幾個不同的.cs文件中,但C#編譯器允許我們將他們放在同一文件中。 4. 局部類型的應(yīng)用特性
在局部類型上的特性具有“累加”效應(yīng)。
[Attribute1, Attribute2("Hello")]
partial class Class1
{
}
[Attribute3, Attribute2("Exit")]
partial class Class1
{
}
相當(dāng)于
[Attribute1, Attribute2("Hello"), Attribute3, Attribute2("Exit")]
class Class1
{
}
注:Attribute2屬性允許在類上多次使用。
5. 局部類型上的修飾符
(1) 一個類型的各個部分上的訪問修飾符必須維持一致性。
(2) 如果一個類型有一個部分使用了abstract修飾符,那么整個類都將被視為抽象類。
(3) 如果一個類型有一個部分使用了 sealed 修飾符,那么整個類都將被視為密封類。
(4) 一個類的各個部分不能使用相互矛盾的修飾符,比如不能在一個部分上使用abstract,又在另一個部分上使用sealed。
6. 局部類型的基類和接口
(1) 一個類型的各個部分上指定的基類必須一致。某個部分可以不指定基類,但如果指定,則必須相同。
(2) 局部類型上的接口具有“累加”效應(yīng)。
partial class Class2: Iinterface1, Iinterface2 {}
partial class Class2: Iinterface3 {}
partial class Class2: Iinterface2 {}
相當(dāng)于
class Class2: Iinterface1, Iinterface2, Iinterface3 {}
posted @
2008-09-10 16:37 天書 閱讀(174) |
評論 (0) |
編輯 收藏
從VS2005開始就不允許非創(chuàng)建此控件的線程來調(diào)用它,那么解決方法是在該控件所在窗體里加上一句話:
CheckForIllegalCrossThreadCalls = false;
private void Form1_Load(object sender, EventArgs e)
{
CheckForIllegalCrossThreadCalls = false;
//信號量
signel sgl = new signel(10);
//新建一個隊列緩沖區(qū)
Queue<int> que = new Queue<int>(10);
Reader readerThread = new Reader(sgl,que,this);
Writer writerThread = new Writer(sgl,que,this);
//開啟兩個線程
Thread tRead = new Thread(readerThread.Process);
Thread tWrite= new Thread(writerThread.Process);
tRead.Start();
tWrite.Start();
}
posted @
2008-09-10 13:14 天書 閱讀(1261) |
評論 (0) |
編輯 收藏
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Collections;
namespace MulThead
{
class signel
{
public Semaphore singleRead;
public Semaphore singleWrite;
public Semaphore singleMutex;
private int size;
public signel(int size)
{
this.size = size;
singleRead = new Semaphore(0,size); //一共size個read資源,目前有0個可用
singleWrite = new Semaphore(size, size); //一共size個write資源,目前有size個可用
singleMutex = new Semaphore(1, 1);
}
}
class Reader
{
private signel sgl;
private Queue<int> que;
private Form1 f1;
//保存信號量和隊列的一個引用
public Reader(signel sgl, Queue<int> que,Form1 f1)
{
this.sgl = sgl;
this.que = que;
this.f1 = f1;
}
public void Process()
{
int readvalue;
while(true)
{
sgl.singleRead.WaitOne();
sgl.singleMutex.WaitOne();
readvalue = que.Dequeue();
f1.txtReader.Text += readvalue.ToString();
f1.txtReader.Text += " ";
sgl.singleMutex.Release();
sgl.singleWrite.Release(); //釋放寫資源
}
}
}
class Writer
{
private signel sgl;
private Queue<int> que;
private Form1 f1;
public Writer(signel sgl, Queue<int> que,Form1 f1)
{
this.sgl = sgl;
this.que = que;
this.f1 = f1;
}
public void Process()
{
int i = 0;
while(i < 50)
{
i++;
sgl.singleWrite.WaitOne();
sgl.singleMutex.WaitOne();
f1.txtWriter.Text += i.ToString();
f1.txtWriter.Text += " ";
que.Enqueue(i);
sgl.singleMutex.Release();
sgl.singleRead.Release(); //釋放讀資源
}
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
CheckForIllegalCrossThreadCalls = false; //這樣在不是創(chuàng)建該控件(此form里的控件)的線程里也可以用這個控件了
//信號量
signel sgl = new signel(10);
//新建一個隊列緩沖區(qū)
Queue<int> que = new Queue<int>(10);
Reader readerThread = new Reader(sgl,que,this);
Writer writerThread = new Writer(sgl,que,this);
//開啟兩個線程
Thread tRead = new Thread(readerThread.Process);
Thread tWrite= new Thread(writerThread.Process);
tRead.Start();
tWrite.Start();
}
posted @
2008-09-10 13:07 天書 閱讀(559) |
評論 (0) |
編輯 收藏
*******ref 有進有出,out只出不進*************************************************************
Ref指明了方法中使用的是引用型參數(shù),引用型參數(shù)不開辟新的內(nèi)存區(qū)域。當(dāng)利用引用型參數(shù)向方法傳遞形參時,編譯程序?qū)褜嶋H值在內(nèi)存中的地址傳遞該方法。引用型參數(shù)通常已經(jīng)初始化。
如
int i=1,j=2; //初始化在函數(shù)外面 Swap(
ref i,
ref j);
Out輸出型參數(shù)也不開辟新的內(nèi)存區(qū)域,但與引用型參數(shù)不同的是,調(diào)用方法之前無需對變量進行初始化,輸出型參數(shù)主要用于傳遞方法返回的數(shù)據(jù)。
string name,path; //沒有初始化,初始化在函數(shù)里面 File(out name,out path);
學(xué)過C/C++的人,對C#的關(guān)鍵字Ref和Out應(yīng)該都很好理解。它們都提供了一種可以在被調(diào)用函數(shù)內(nèi)修改傳遞的參數(shù)的值的方法。因為這一功能很類似C/C++的指針。對于沒學(xué)過C/C++的,也應(yīng)該可以明白這兩個參數(shù)的作用。
雖然Ref和Out都提供了修改參數(shù)值的方法,但它們還是有一點點小的區(qū)別。
1、Ref在作為參數(shù)調(diào)用函數(shù)之前,變量一定要賦值,否則會得到一個常規(guī)編譯錯誤:使用了未賦值的變量。
2、在被調(diào)用函數(shù)內(nèi),以Ref引入的參數(shù)在返回前不必為它賦值。
3、Out在作為參數(shù)調(diào)用函數(shù)之前,變量可以不被賦值。
4、在被調(diào)用函數(shù)內(nèi),以O(shè)ut引入的參數(shù)在返回前一定要至少賦值一次。其實本質(zhì)上講,Ref更適合理解為給被調(diào)用函數(shù)傳遞了一個與原參考同地址的變量。而Out則可以理解為在調(diào)用函數(shù)前,先給變量找個地方,讓被調(diào)用函數(shù)在給定地點放一個值。
posted @
2008-09-10 10:01 天書 閱讀(609) |
評論 (0) |
編輯 收藏
《Effective C#》:值類型和引用類型
在C#中有兩種類型的數(shù)據(jù),一種是值類型數(shù)據(jù),一種是引用類型數(shù)據(jù)。在編碼的時候區(qū)分這兩種類型數(shù)據(jù),可以避免一些細小的編碼錯誤。
首先說說什么類型是值類型,例如:int、float、bool之類的基礎(chǔ)類型,以及用struct定義的類型,如:DateTime。除此外,如string,數(shù)組,以及用class定義的類型等都是引用類型。對于C#來說,很難羅列出所有類型進行一一分別,這需要自己在編碼過程中進行分析總結(jié)。
為了更好地說明兩種類型之間的區(qū)別,借用如下的表格來說明。
|
值類型 |
引用類型 |
內(nèi)存分配地點 |
分配在棧中 |
分配在堆中 |
效率 |
效率高,不需要地址轉(zhuǎn)換 |
效率低,需要進行地址轉(zhuǎn)換 |
內(nèi)存回收 |
使用完后,立即回收 |
使用完后,不是立即回收,等待GC回收 |
賦值操作 |
進行復(fù)制,創(chuàng)建一個同值新對象 |
只是對原有對象的引用 |
函數(shù)參數(shù)與返回值 |
是對象的復(fù)制 |
是原有對象的引用,并不產(chǎn)生新的對象 |
類型擴展 |
不易擴展 |
容易擴展,方便與類型擴展 |
通過如上細致對比,大家對于值類型和引用類型有個清楚的概念。
不過,無論是對于值類型還是引用類型來說,對于其作為函數(shù)參數(shù)或者返回值的時候,都是容易犯錯誤的地方。
對于值類型來說,當(dāng)其作為函數(shù)參數(shù)的時候,希望在函數(shù)中被修改,那么直接如下操作是不能被修改的。
public void Increment( int i ) { i++; } |
要想在函數(shù)中對傳進去的參數(shù)做真正的修改,需要借助于ref這個關(guān)鍵字,那么正確的形式如下。
public void Increment( ref int i )
|
也就是說,如果需要在函數(shù)中對值類型參數(shù)進行修改,需要用ref或者out進行標(biāo)識才能真正實現(xiàn)。
而對于引用類型來說,當(dāng)其作為函數(shù)參數(shù)的時候,它所遇到的情況恰恰與值類型相反,即不希望在函數(shù)中被修改,舉例如下。
public void AddValue( MyType typValue ) { typValue.Count = typValue.Count + 15; } |
由于對于引用類型對象來說,其的賦值操作只是對原有對象的引用,因此在函數(shù)對其修改,實際上是直接修改了原有對象數(shù)據(jù),這是很多情況不希望發(fā)生的(這里例如對數(shù)組或者DataTable操作這類)。
為了防止這種事發(fā)生,需要給此類型提供clone函數(shù)。例如對于如上的類型,可以入下實現(xiàn)。
public class MyType:ICloneable { private int nCount = 0; public int Count { set{ nCount = value;} get{ return nCount;} } public MyType() {} public MyType( int Value) { nCount = Value; }
#region ICloneable Members
public object Clone() { // TODO: Add MyType.Clone implementation return new MyType( nCount ); }
#endregion }
|
那么在調(diào)用的時候,用當(dāng)前的對象的clone作為參數(shù)即可。
不過對于引用類型來說,提供一個clone函數(shù)不是一件容易的事情,尤其出現(xiàn)引用類型嵌套的時候,所以說去實現(xiàn)一個完全clone功能是件很費事又不討好的活,這也就是在論壇中常說的深copy和淺copy的問題。話雖如此,如果對于前面所說的有個大概了解,相信實現(xiàn)也不是不可能。
在C#中,尤其自己定義類型的時候,常常由于是用struct來定義還是用class來定義,即是定義一個值類型還是一個引用類型呢。在這本書上給了幾個判定條件,如果如下幾點都滿足的話,建議用struct來定義為值類型,否則用class定義為引用類型。
<!--[if !supportLists]-->1. <!--[endif]-->這個類型是否主要為了數(shù)據(jù)存儲; <!--[if !supportLists]-->2. <!--[endif]-->是否只通過屬性來訪問對象的數(shù)據(jù)成員; <!--[if !supportLists]-->3. <!--[endif]-->這個類型是否不會有子類型; <!--[if !supportLists]-->4. <!--[endif]-->在程序處理的時候不會把這個類型對象通過多態(tài)來處理。 |
posted @
2008-09-10 09:43 天書 閱讀(179) |
評論 (0) |
編輯 收藏
首先:窗體的兩個屬性 AcceptButton ,和 CancelButton 分別設(shè)置為窗體上“確定”和“取消”按鈕的名字:bnok 和 bncancel.
其次:確定按鈕和取消按鈕的"DialogResult"屬性分別設(shè)置為:ok , cancel
然后:窗體上的控件textbox要在類外部讀出來那么設(shè)置其 modifier屬性為public即可
接著:
int errCount = 0;
while (errCount < 3)
{
FrmLogin flog = new frmLogin();
flog.ShowDialog(this);
if (flog.DialogResult == DialogResult.OK)
{
flog.Username = flog.txtusername.Text;
flog.Password = flog.txtpassword.Text;
if (flog.Username == "liumu" &&
flog.Password == "198331622")
{
MessageBox.Show("歡迎訪問該系統(tǒng)", "登錄成功");
ShowWelcomePage();
break;
}
else
{
errCount++;
MessageBox.Show("用戶名或密碼有誤請核對后重新輸入", "錯誤提示");
}
}
else if (flog.ShowDialog() == DialogResult.Cancel)
{
Application.Exit();
}
}
if (errCount == 3)
{
MessageBox.Show("您三次輸入有誤,被迫推出系統(tǒng),Sorry!", "退出提示");
Application.Exit();
}
posted @
2008-09-09 13:23 天書 閱讀(2174) |
評論 (0) |
編輯 收藏
1:對象在類內(nèi)部實例化且僅一次
2:構(gòu)造函數(shù)私有
3:用屬性get將對象讀出來,如果為空那么實例化一次如:
public class Singleton
{
static Singleton instance = null;
private Singleton()
{
}
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
posted @
2008-09-08 16:58 天書 閱讀(90) |
評論 (0) |
編輯 收藏
public class File
{
string fileName;
public File(string fileName)
{
this.fileName=fileName;
}
public string ReadFile()
{
try
{
StreamReader sr=new StreamReader(fileName,Encoding.Default);
string result=sr.ReadToEnd();
sr.Close();
return result;
}
catch(Exception e){MessageBox.Show(e.Message);}
return null;
}
public void WriteFile(string str)
{
try
{
StreamWriter sw=new StreamWriter(fileName,false,Encoding.Default);
sw.Write(str);
sw.Close();
}
catch(Exception e){MessageBox.Show(e.Message,"保存文件出錯!");}
}
}
posted @
2008-09-05 14:26 天書 閱讀(528) |
評論 (0) |
編輯 收藏
private static void SetTreeViewIcon(TreeView tv, NodeType firstType, NodeType secondType, NodeType thirdType)
{
TreeNode tnRoot = tv.Nodes[0];
tnRoot.ImageIndex = 0;
foreach (TreeNode tnFirst in tnRoot.Nodes)
{
tnFirst.ImageIndex = tnFirst.SelectedImageIndex = (int)firstType;
foreach (TreeNode tnSecond in tnFirst.Nodes)
{
tnSecond.ImageIndex = tnSecond.SelectedImageIndex = (int)secondType;
foreach (TreeNode tnThird in tnSecond.Nodes)
{
tnThird.ImageIndex = tnThird.SelectedImageIndex = (int)thirdType;
}
}
}
}
posted @
2008-09-04 20:43 天書 閱讀(510) |
評論 (0) |
編輯 收藏
首先在form窗體上拖上一個
ImageList控件,在屬性窗口中設(shè)置它的Image屬性即導(dǎo)入幾個圖標(biāo),圖標(biāo)都是有索引的。接著在程序中寫上一句代碼:
myNeTree.ImageList = NeImgList; myNeTree為你在程序中事先定義好的如:private TreeView myNeTree;最后在寫樹節(jié)點的時候設(shè)置
ImageIndex 屬性 :
typenode.ImageIndex = 1;要想讓節(jié)點選上時變圖標(biāo)要設(shè)置節(jié)點的SelectedImageIndex屬性typenode.SelectedImageIndex = 3; 像1,3都是ImageList中圖標(biāo)的索引值
posted @
2008-09-04 16:16 天書 閱讀(7843) |
評論 (0) |
編輯 收藏