首先關於資料庫的開啟可考慮兩種方式
1.用using{...}區塊
using(SqlConnection con = new SqlConnection())
{
con.ConnectionString = "....";
con.Open();
....
}
這種方法會在脫離區塊後立刻釋放Connection物件的資源
所以不用使用資料庫的關閉方法(如Close()、Dispose())
另外就是正規的寫法
2.
using System.Data.SqlClient;
....
SqlConnection con = new SqlConnection("xxx"); //xxx = connection string
SqlCommand cmd = new SqlCommand("xxx", con); //xxx = SQL command
SqlDataReader dr;
...
con.Open();
dr = cmd.ExecuteReader(); //使用DataReader物件讀取資料庫內容
...
con.Close();
SqlCommand物件的幾個常用方法跟屬性
ExecuteNonQuery() -
可以執行INSERT、UPDATE、DELETE等SQL command,成功時回傳受影響的紀錄筆數
ExecuteScalar() -
適用於結果集只回傳一個資料列的第一欄,例如SQL command 的COUNT()、MAX()等
ExecuteReader() -
執行Command物件中所指定的SQL的SELECT敘述,並建立一個DataReader來瀏覽資料
CommandText -
設定或取得要執行的命令
SqlCommand使用範例:
string sqlStr = string.Empty;
sqlStr = "INSERT INTO TableA(姓名, 聯絡方式, 薪水)" + "VALUES(@name, @tel, @pay)"
SqlCommand cmd = new SqlCommand( sqlStr , con);
cmd.CommandType = CommandType.StoreProcedure; //預先編譯SQL處理函式
cmd.Parameters.Add(new SqlParameter("@name", SqlDbType.NVarChar));
cmd.Parameters.Add(new SqlParameter("@tel", SqlDbType.NVarChar));
cmd.Parameters.Add(new SqlParameter("@pay", SqlDbType.NVarChar));
cmd.Parameters["@name"].Value = "vc56";
cmd.Parameters["@tel"].Value = "0000000";
cmd.Parameters["@pay"].Value = "$20000";
cmd.ExecuteNonQuery();
DataReader有幾個方法跟屬性較為重要,以下列出:
FieldCount屬性 -
將已查詢欄位的總數傳回
Read() -
將指標移到下一筆,並判斷是否指到EOF
如果到資料結尾則回傳false
Item[i] -
取得第i欄的資料內容
Item["欄位名稱"]集合 -
取得指定欄位名稱所指的資料內容
GetValue(i) -
取得第i欄位的資料內容,傳回值為object資料型別
IsDBNull(i) -
判斷第i個欄位使否為資料庫Null值
使用範例:
while(dr.Read())
{
for(int i = 0; i < dr.FieldCount; i++)
{
textBox1.Text += dr[i].ToString() + "\t";
}
}
以執行效率來說,使用索引會比使用欄位名稱還快
此外,取出時可使用方法來省略手動轉型的動作,如下:
while(dr.Read())
{
textBox1.Text += dr.GetString(0) + "\t";
textBox1.Text += dr.GetInt32(1).ToString() + "\t";
...
}
DataSet則是ADO.NET的特色
他會先將資料庫的內容存至記憶體中,並得以執行離線操作
操作完畢後再將內容回寫至資料庫中
適用於多用戶端資料存取,當然占用的記憶體多是不可避免的事
DataSet中可以包含一個以上的DataTable物件
由DataAdapter使用Command物件執行SQL command
再將取得的資料寫至DataSet,如此就能用DataTable存取資料表,範例:
using System.Data.SqlClient;
using System.Data;
.....
using(SqlConnection con = new SqlConnection())
{
con.ConnectionString = "....";
DataSet ds = new DataSet();
SqlDataAdapter dsContent = new SqlDataAdapter("xxx", con); //xxx = sql command
dsContent.Fill(ds, "Content"); //使用Fill()時,DataAdapter會自動連線到資料庫
/*
Adapter也可以改成SqlDataAdapter dsContent = new SqlDataAdapter();
dsContent.SelectCommand = cmd;
這樣就可以使用SqlCommand物件來保持彈性
另外有幾種特性語法示範
int n = ds.Tables.Count; //取得DataSet中DataTable的總數
String tName = ds.Table[i].TableName; //取得第i個DataTable的表格名稱
*/
DataTable dt = ds.Tables["Content"]; //對應SqlDataAdapter Fill ()時填入的資料表名
for(int i = 0; i < dt.Rows.Count; i++)
{
for(int j = 0; j < dt.Columns.Count; j++)
{
textBox1.Text += dt.Rows[i][j].ToString() + "\t";
}
textBox1.Text += Enviroment.NewLine;
}
}
....
DataSet另外尚有使資料表之間產生關連的操作
ds.Realations.Add( "關聯名稱",
ds.Tables["dt1"].Columns["dt1要關聯的欄位名稱"],
ds.Tables["dt2"].Columns["dt2要關聯的欄位名稱"],
)
日後可與DataView物件結合使用
dataGridView1.DataSource = ds;
dataGridView1.DataMember = "dt1";
dataGridView2.DataSource = ds;
dataGridView2.DataMember = "dt1.關聯名稱";
2012年7月5日 星期四
2012年7月3日 星期二
[轉貼] C# 淺析SqlConnection的dispose和close方法差異
原文
引用微軟ADO.Team的經理的話說,sqlconnection的close和dispose實際是做的同一件事,
唯一的區別是Dispose方法清空了connectionString,即設置為了null.
SqlConnection con = new SqlConnection("Data Source=localhost;Initial Catalog=northwind;User ID=sa;Password=steveg");
con.Open();
con.Close();
con.Open();
con.Dispose();
con.Open();
dispose的不行,因為connectionstring清空了,
會拋出InvalidOperationException提示The ConnectionString property has not been initialized,
但請注意此時sqlconnection對象還在。
如果dispose後給connectionString重新賦值,則不會報錯。
由此得出的結論是不管是dispose還是close都不會銷毀對象,即不會釋放內存,
它們會把sqlconnection對象丟到連接池中,那此對象什麼時候銷毀呢?
我覺得應該是connection timeout設置的時間內,
如果程序中沒有向連接池發出請求說要connection對象,sqlconnection對象便會銷毀,
這也是連接池存在的意義。
剛開始以為dispose會釋放資源清空內存,
如果這樣的話,連接池不是每次都是要創建新對象,那何來重用connection呢?
在網上看到很多人說close比dispose好,
我想真正的原因是dispose後的sqlconnection對象要重新初始化連接字符串而已,
並不是像某些人說的dispose會釋放對象。
所以在try..catch和using的選擇上大膽的使用using吧,
真正的效率差異我想可能只有百萬分之一秒吧
(連接池重用該連接對象初始化連接字符串的時間),
而且enterprise library中封裝的data access層全是用的using,
從代碼的美觀和效率上綜合考慮,using好
補充:
using不會捕捉其代碼快中的異常,
只會最後執行dispose方法,相當於finally{dispose},
本文主要是想說明dispose和close的差異,因為using是絕對dispose的,
可是如果人為的寫try..finally有的人會選擇close有的人會選擇dispose,
實際上在這2者的選擇上是有差異的。
引用微軟ADO.Team的經理的話說,sqlconnection的close和dispose實際是做的同一件事,
唯一的區別是Dispose方法清空了connectionString,即設置為了null.
SqlConnection con = new SqlConnection("Data Source=localhost;Initial Catalog=northwind;User ID=sa;Password=steveg");
con.Open();
con.Close();
con.Open();
con.Dispose();
con.Open();
dispose的不行,因為connectionstring清空了,
會拋出InvalidOperationException提示The ConnectionString property has not been initialized,
但請注意此時sqlconnection對象還在。
如果dispose後給connectionString重新賦值,則不會報錯。
由此得出的結論是不管是dispose還是close都不會銷毀對象,即不會釋放內存,
它們會把sqlconnection對象丟到連接池中,那此對象什麼時候銷毀呢?
我覺得應該是connection timeout設置的時間內,
如果程序中沒有向連接池發出請求說要connection對象,sqlconnection對象便會銷毀,
這也是連接池存在的意義。
剛開始以為dispose會釋放資源清空內存,
如果這樣的話,連接池不是每次都是要創建新對象,那何來重用connection呢?
在網上看到很多人說close比dispose好,
我想真正的原因是dispose後的sqlconnection對象要重新初始化連接字符串而已,
並不是像某些人說的dispose會釋放對象。
所以在try..catch和using的選擇上大膽的使用using吧,
真正的效率差異我想可能只有百萬分之一秒吧
(連接池重用該連接對象初始化連接字符串的時間),
而且enterprise library中封裝的data access層全是用的using,
從代碼的美觀和效率上綜合考慮,using好
補充:
using不會捕捉其代碼快中的異常,
只會最後執行dispose方法,相當於finally{dispose},
本文主要是想說明dispose和close的差異,因為using是絕對dispose的,
可是如果人為的寫try..finally有的人會選擇close有的人會選擇dispose,
實際上在這2者的選擇上是有差異的。
2012年7月1日 星期日
C# 文字控制項-自動完成輸入功能
C#的自動完成功能提供了當使用者在文字方塊中輸入的資料符合條件時
便會自動填入或彈出符合的字串以提升使用者輸入資料的效率
TextBox或ComboBox 中的三個屬性須注意:
AutoCompleteSource、AutoCompleteMode、AutoCompleteCustomSource
AutoCompleteSource的常用屬性值包括
1.HistoryList - 以URL中的歷史清單作為自動完成輸入功能的來源
ex:textBox1.AutoCompleteSource = AutoCompleteSource.HistoryList;
程式碼部分以下類推
2.RecentlyUsedList - 以URL中的歷史清單和最近瀏覽過的URL為來源
3.AllUrl - 以最近瀏覽過的URL作為自動完成輸入功能的來源
4.FileSystem - 以檔案系統為來源
5.FileSystemDirectories - 以磁碟和目錄為來源,不包括檔案
6.AllSystemSources - 以AllUrl和FileSystem為來源
7.None - 取消自動完成輸入功能來源
8.CustomSource - 自訂來源,須搭配AutoCompleteCustomSource屬性設定
AutoCompleteMode常用屬性
1.Append - 將最可能相符之候選字串其餘部分附加到現有字串之後,並反白顯示
ex:textBox1.AutoCompleteMode = AutoCompleteMode.Append;
2.Suggest - 挑選出最符合的字串於下拉選單的選項中
3.SuggestAppend - 混用上述兩種功能
4.None - 停用自動完成輸入功能
AutoCompleteCustomSource屬性
除了直接在Widget屬性介面上設計外
也可以用程式碼部分撰寫,如:
string[] content = new string[]{"a","b","c"};
AutoCompleteStringCollection newAdd = new AutoCompleteStringCollection();
newAdd.AddRange(content);
textBox1.AutoCompleteMode = AutoCompleteMode.Suggest;
textBox1.AutoCompleteSource = AutoCompleteSource.CustomSource;
textBox1.AutoCompleteCustomSource = newAdd;
便會自動填入或彈出符合的字串以提升使用者輸入資料的效率
TextBox或ComboBox 中的三個屬性須注意:
AutoCompleteSource、AutoCompleteMode、AutoCompleteCustomSource
AutoCompleteSource的常用屬性值包括
1.HistoryList - 以URL中的歷史清單作為自動完成輸入功能的來源
ex:textBox1.AutoCompleteSource = AutoCompleteSource.HistoryList;
程式碼部分以下類推
2.RecentlyUsedList - 以URL中的歷史清單和最近瀏覽過的URL為來源
3.AllUrl - 以最近瀏覽過的URL作為自動完成輸入功能的來源
4.FileSystem - 以檔案系統為來源
5.FileSystemDirectories - 以磁碟和目錄為來源,不包括檔案
6.AllSystemSources - 以AllUrl和FileSystem為來源
7.None - 取消自動完成輸入功能來源
8.CustomSource - 自訂來源,須搭配AutoCompleteCustomSource屬性設定
AutoCompleteMode常用屬性
1.Append - 將最可能相符之候選字串其餘部分附加到現有字串之後,並反白顯示
ex:textBox1.AutoCompleteMode = AutoCompleteMode.Append;
2.Suggest - 挑選出最符合的字串於下拉選單的選項中
3.SuggestAppend - 混用上述兩種功能
4.None - 停用自動完成輸入功能
AutoCompleteCustomSource屬性
除了直接在Widget屬性介面上設計外
也可以用程式碼部分撰寫,如:
string[] content = new string[]{"a","b","c"};
AutoCompleteStringCollection newAdd = new AutoCompleteStringCollection();
newAdd.AddRange(content);
textBox1.AutoCompleteMode = AutoCompleteMode.Suggest;
textBox1.AutoCompleteSource = AutoCompleteSource.CustomSource;
textBox1.AutoCompleteCustomSource = newAdd;
2012年6月27日 星期三
[轉貼] Business or Geek?
原文
這個話題來自於華蟒用戶組郵件列表2010年1月的一個貼子,因為我本身不是該組的訂閱者,最近無意中搜索到,覺得有點意思就分享一些想法。
通常想創業的同學應該也遇到過這樣的一些情況,你有一個想法需要想集思廣益地跟大家分享討論,以便*期待*得到更多的人認同,從而再去推進行動。這裡的討論也由一位叫sliuqin的同學展開,他希望跟老婆想要做一個賣茶的電子商務網站:
*創業項目*: 獨立電子商務網站,主營:茶葉和茶葉相關商品。
*項目優勢*: 老爸是開茶葉店的。
*項目開發:* 週期:10個月 人員:
- 我,負責網站後台開發(Ubuntu server + python + django) - 我老婆,負責前端開發,用戶體驗和視覺設計。
項目資金:10w,包含我們一年的生活費,和後期的服務器等,吃住在家裡(做寄生蟲)
現在我們開始了一部分工作,但是是公司工作之餘,我們兩個人的人生經歷還少,我本身也沒有做過專業的python開發,所以想聽聽大家的意見:這個計劃*可行嗎* ? 但這裡討論的不是這個項目是否可行,我想說的如同以下兩位
Business是事業,geek是愛好。當然,我從不認為純技術流不能創造一家賺錢的互聯網公司,這樣的公司在互聯網行業中俯首皆是。而且還有部分互聯網公司出現的時候就不知道該怎麼盈利,也就總會有聽到說:「等我們的用戶數足夠大了,我們就會想到盈利方式。」但如果我們認為這些創業者們沒有想過怎麼去「Business」的話,那我想一定是我搞錯了一些東西,他們有想,他們有想得到的某個固定人群,通過技術和人群建立競爭壘壁,爭奪人群本身就是一項「商業」。所以他們選擇了快速開發讓市場去驗證終端需求,而絕對不會在技術的選擇上浪費太多的時間。
繼續拿<REWORK>說事,」start with business, not a startup」說的就是這個意思,從一開始就想辦法賺錢,行動起來!別用10個月時間+不熟悉的python來做一個電子商店了,架個開源網店就開賣吧,兄弟。
這個話題來自於華蟒用戶組郵件列表2010年1月的一個貼子,因為我本身不是該組的訂閱者,最近無意中搜索到,覺得有點意思就分享一些想法。
通常想創業的同學應該也遇到過這樣的一些情況,你有一個想法需要想集思廣益地跟大家分享討論,以便*期待*得到更多的人認同,從而再去推進行動。這裡的討論也由一位叫sliuqin的同學展開,他希望跟老婆想要做一個賣茶的電子商務網站:
*關於我們*: 目前,我們分別在兩家大型的電子商務公司做*前端開發*,工作2年了。朝九晚六的工作雖然挺安逸,但不是自己想要的,對!我們想創業了。
*創業項目*: 獨立電子商務網站,主營:茶葉和茶葉相關商品。
*項目優勢*: 老爸是開茶葉店的。
*項目開發:* 週期:10個月 人員:
- 我,負責網站後台開發(Ubuntu server + python + django) - 我老婆,負責前端開發,用戶體驗和視覺設計。
項目資金:10w,包含我們一年的生活費,和後期的服務器等,吃住在家裡(做寄生蟲)
現在我們開始了一部分工作,但是是公司工作之餘,我們兩個人的人生經歷還少,我本身也沒有做過專業的python開發,所以想聽聽大家的意見:這個計劃*可行嗎* ? 但這裡討論的不是這個項目是否可行,我想說的如同以下兩位
- @john : 「你是想賣茶葉啊,還是想賣網站?」
- @誠子 : 「business or geek?」
Business是事業,geek是愛好。當然,我從不認為純技術流不能創造一家賺錢的互聯網公司,這樣的公司在互聯網行業中俯首皆是。而且還有部分互聯網公司出現的時候就不知道該怎麼盈利,也就總會有聽到說:「等我們的用戶數足夠大了,我們就會想到盈利方式。」但如果我們認為這些創業者們沒有想過怎麼去「Business」的話,那我想一定是我搞錯了一些東西,他們有想,他們有想得到的某個固定人群,通過技術和人群建立競爭壘壁,爭奪人群本身就是一項「商業」。所以他們選擇了快速開發讓市場去驗證終端需求,而絕對不會在技術的選擇上浪費太多的時間。
繼續拿<REWORK>說事,」start with business, not a startup」說的就是這個意思,從一開始就想辦法賺錢,行動起來!別用10個月時間+不熟悉的python來做一個電子商店了,架個開源網店就開賣吧,兄弟。
- 問某遊戲公司CEO:「你們都用什麼技術?」答:「沒關係,用最熟悉的PHP。」
- 問手機遊戲開發者:「如何切入移動開發,iOS or Android?」答:「Android,因為我熟悉Java 。」
[轉貼] 為何我們要從Node.JS遷移到Ruby on Rails
原文
聲明:這篇文章絕不是一篇討論Node.JS和Ruby on Rails孰優孰略的檄文。它描述的只是我們做決策過程中的一些思考、決策背後的原因。兩種框架都非常優秀,都出色的完成了它們的設計初衷,這也是為什麼我們部分的模塊仍然運行在Node.JS上的原因。
我是Node.JS的大粉絲,認為這是一項讓人非常興奮的技術,相信它會變的越來越流行。我對這項技術非常的欣賞——儘管我們最近把Targeter App從Node.JS遷移到了Ruby on Rails。
我們當時使用Node.JS開發它的原因很簡單。我有一個程序包,能很快的將我們的應用弄上線(我們花了54小時做這個事情),相比起Ruby,我更常使用的是JavaScript。因為我們的技術架構牽涉到MongoDB,我的這些特長只有在Node.JS環境裡才會有意義。然而,隨著應用規模的增長,我認識到,選擇Node.JS來實現這個應用是個錯誤的選擇。下面讓我來概述一下其中的原因。
Node.JS很適合做那些有大量短生命期請求的應用。對於傳統的CRUD應用,它也很好,但不是非常的理想。在PHP,Ruby,Python語言裡都有很成熟、優化的很好的框架來處理這種應用。Node.JS裡的所有東西都異步執行的理念對於CRUD應用來說沒有任何效果。其它語言裡的流行的框架能提供非常好的緩存技術,你所有的需求都能滿足,包括異步執行。
Node.JS是一種非常年輕的技術框架,它的周邊程序庫都不是很成熟。我說這些並沒有任何對那些代碼捐贈者冒犯的意思,他們很優秀,開發出來很多優秀的程序庫。然而,大部分程序庫需要改進,而Node.JS的這種快速成長的環境意味著每一版升級中都帶有大量的變化;當你使用一種前沿技術時,你十分有必要盡快的緊跟最新的版本。這給創業型的企業帶來了很多的麻煩。
另外一個原因是關於測試。Node.JS裡的測試框架還不錯,但跟Django或RoR平台上的相比還是差一些。對於一個每天都有大量的代碼提交、並且在一兩天內就要發佈的應用來說,程序不能出問題是至關重要的,否則你為此辛苦的努力變得得不償失。沒有人願意花一天的時間改一些弱智的bug。 最後一點,我們需要的是一種能緩存一切的東西,並且要盡快的實現。儘管我們的應用在增長,每秒鐘有上萬次的hits,但絕不會出現很大量的訪問請求;這不是一個聊天程序!主程序最多時也就達到1000RPS,這樣的負載對於Ruby on Rails和Nginx來說算不了什麼。
如果你現在還在讀這篇文章,那你已經看到了我所有要說的了,你也許非常堅持的想知道我們的應用什麼地方還在使用Node.JS。是這樣的,我們的應用由兩部分組成。一是界面,用戶看到的這部分,二是負責報表管理的部分,以及做日誌的功能。後者是Node.JS的一個最佳使用場景,存在有大量的短週期的請求。這部分的動作需要盡快的執行完成,甚至要在我們的數據推送還沒有完成之前。這很重要,當請求執行還未結束,瀏覽器繼續等待響應結束,這會影響用戶使用體驗。Node.JS的異步特性救了我們。數據要麼被存入數據庫,要麼被處理掉,當請求一旦執行完成,瀏覽器就可以開始做其它重要的事情了。
聲明:這篇文章絕不是一篇討論Node.JS和Ruby on Rails孰優孰略的檄文。它描述的只是我們做決策過程中的一些思考、決策背後的原因。兩種框架都非常優秀,都出色的完成了它們的設計初衷,這也是為什麼我們部分的模塊仍然運行在Node.JS上的原因。
我是Node.JS的大粉絲,認為這是一項讓人非常興奮的技術,相信它會變的越來越流行。我對這項技術非常的欣賞——儘管我們最近把Targeter App從Node.JS遷移到了Ruby on Rails。
我們當時使用Node.JS開發它的原因很簡單。我有一個程序包,能很快的將我們的應用弄上線(我們花了54小時做這個事情),相比起Ruby,我更常使用的是JavaScript。因為我們的技術架構牽涉到MongoDB,我的這些特長只有在Node.JS環境裡才會有意義。然而,隨著應用規模的增長,我認識到,選擇Node.JS來實現這個應用是個錯誤的選擇。下面讓我來概述一下其中的原因。
Node.JS很適合做那些有大量短生命期請求的應用。對於傳統的CRUD應用,它也很好,但不是非常的理想。在PHP,Ruby,Python語言裡都有很成熟、優化的很好的框架來處理這種應用。Node.JS裡的所有東西都異步執行的理念對於CRUD應用來說沒有任何效果。其它語言裡的流行的框架能提供非常好的緩存技術,你所有的需求都能滿足,包括異步執行。
Node.JS是一種非常年輕的技術框架,它的周邊程序庫都不是很成熟。我說這些並沒有任何對那些代碼捐贈者冒犯的意思,他們很優秀,開發出來很多優秀的程序庫。然而,大部分程序庫需要改進,而Node.JS的這種快速成長的環境意味著每一版升級中都帶有大量的變化;當你使用一種前沿技術時,你十分有必要盡快的緊跟最新的版本。這給創業型的企業帶來了很多的麻煩。
另外一個原因是關於測試。Node.JS裡的測試框架還不錯,但跟Django或RoR平台上的相比還是差一些。對於一個每天都有大量的代碼提交、並且在一兩天內就要發佈的應用來說,程序不能出問題是至關重要的,否則你為此辛苦的努力變得得不償失。沒有人願意花一天的時間改一些弱智的bug。 最後一點,我們需要的是一種能緩存一切的東西,並且要盡快的實現。儘管我們的應用在增長,每秒鐘有上萬次的hits,但絕不會出現很大量的訪問請求;這不是一個聊天程序!主程序最多時也就達到1000RPS,這樣的負載對於Ruby on Rails和Nginx來說算不了什麼。
如果你現在還在讀這篇文章,那你已經看到了我所有要說的了,你也許非常堅持的想知道我們的應用什麼地方還在使用Node.JS。是這樣的,我們的應用由兩部分組成。一是界面,用戶看到的這部分,二是負責報表管理的部分,以及做日誌的功能。後者是Node.JS的一個最佳使用場景,存在有大量的短週期的請求。這部分的動作需要盡快的執行完成,甚至要在我們的數據推送還沒有完成之前。這很重要,當請求執行還未結束,瀏覽器繼續等待響應結束,這會影響用戶使用體驗。Node.JS的異步特性救了我們。數據要麼被存入數據庫,要麼被處理掉,當請求一旦執行完成,瀏覽器就可以開始做其它重要的事情了。
[轉貼] C# Delegate/event 的簡單理解
看這篇前可以先看這篇文章瞭解Delegate的語法與使用方式
本篇原文=================
簡單來說就是增加一層間接層來實現晚綁定,從而獲得更為鬆散的耦合
為什麼要有Delegate?
假設有兩個不同類實現的對象A和B,A和B分別有方法a和b。現在需要a方法以一觸發,便執行對象B的方法b。 不使用delegate,我們可以在設計A類的時候在將B類作為參數傳入a方法,這樣可以實現我們的要求。但是這樣做有明顯的缺陷:
1. 我們需要事先知道B類。
2. 如果還存在C類、D類等的方法需要一併執行,這樣必須重新修改A類的代碼。 如果有了 Delegate,我們可以事先設計一個函數指針,這樣當對象A執行a方法的時候,就可以根據該指針指向的,符合該函數指針法則的方法進行執行。這樣,我們就不需要在設計A類的時候知道B類,只需要知道B的b方法的參數和返回值就可以了。如果還有C類、D類方法需要一併執行,也可以添加到該指針指向的數據結構中。
示例代碼分析:
public delegate void Delegate_A(); 這個語句規定了函數指針指向的函數應該符合的規範:沒有返回值,沒有參數傳入。
2. 接著實例化了一個 Delegate_A的對象da,這裡使用event關鍵字表明它是一個事件。
3. 再看Class B的的構造函數,可見B構造時,往對象a的事件中傳入了Method_B的函數地址(a.da += new A.Delegate_A(Method_B))
4. 在Main函數中執行A對象的Method_A時,觸發了事件da,而da指向了B的方法。這樣即便A對象對B對象一無所知,也同樣能執行B的方法Method_B。這就是Delegate的好處。
Event有什麼用:
實際上在上例中將Event關鍵字刪除程序同樣能執行。之所以要加上Event,是因為在程序編譯時,加上Event以後該Delegate的對象會成為該類的私有成員,這樣外界只能通過 += 和 -=來對Delegate的對象da進行操作,而不能直接進行賦值。
本篇原文=================
簡單來說就是增加一層間接層來實現晚綁定,從而獲得更為鬆散的耦合
為什麼要有Delegate?
假設有兩個不同類實現的對象A和B,A和B分別有方法a和b。現在需要a方法以一觸發,便執行對象B的方法b。 不使用delegate,我們可以在設計A類的時候在將B類作為參數傳入a方法,這樣可以實現我們的要求。但是這樣做有明顯的缺陷:
1. 我們需要事先知道B類。
2. 如果還存在C類、D類等的方法需要一併執行,這樣必須重新修改A類的代碼。 如果有了 Delegate,我們可以事先設計一個函數指針,這樣當對象A執行a方法的時候,就可以根據該指針指向的,符合該函數指針法則的方法進行執行。這樣,我們就不需要在設計A類的時候知道B類,只需要知道B的b方法的參數和返回值就可以了。如果還有C類、D類方法需要一併執行,也可以添加到該指針指向的數據結構中。
示例代碼分析:
代碼
1. 先看Class A中 class Program
{
static void Main(string[] args)
{
A a = new A();
B b = new B(a);
a.Method_A();
}
}
class A
{
public delegate void Delegate_A();
public event Delegate_A da;
public void Method_A()
{
da();
}
}
class B
{
public B(A a)
{
a.da += new A.Delegate_A(Method_B);
}
public void Method_B()
{
Console.WriteLine("B's method!");
}
}
public delegate void Delegate_A(); 這個語句規定了函數指針指向的函數應該符合的規範:沒有返回值,沒有參數傳入。
2. 接著實例化了一個 Delegate_A的對象da,這裡使用event關鍵字表明它是一個事件。
3. 再看Class B的的構造函數,可見B構造時,往對象a的事件中傳入了Method_B的函數地址(a.da += new A.Delegate_A(Method_B))
4. 在Main函數中執行A對象的Method_A時,觸發了事件da,而da指向了B的方法。這樣即便A對象對B對象一無所知,也同樣能執行B的方法Method_B。這就是Delegate的好處。
Event有什麼用:
實際上在上例中將Event關鍵字刪除程序同樣能執行。之所以要加上Event,是因為在程序編譯時,加上Event以後該Delegate的對象會成為該類的私有成員,這樣外界只能通過 += 和 -=來對Delegate的對象da進行操作,而不能直接進行賦值。
2012年6月26日 星期二
C# 物件配置與記憶體議題
對於實值型別(等同Java中稱的基本型別)一樣是放在stack
在method中也同樣是以複製的形式傳遞
也就是method中作的變動不會影響到原本的實值型別物件
不過若要改變傳遞的形式則可以使用 ref、out 兩個關鍵字
ref的用法為宣告使用call by reference
如:public void swap(ref int x, ref int y){ ... //code for swap x&y }
使用method時亦用ref,如:
int a = 1; int b = 2;
swap(ref a, ref b);
如此一來a與b的值就會在method呼叫過後改變了
C#在配置物件(參考型別資料)時亦隱含了ref的宣告
所以省略不寫也沒關係
但若明白的了ref宣告
則必須在參數、引述的地方都宣告,否則會引起編譯錯誤,如:
public void dosth(ref int[,] intary){ .... }
int[,] a = new int[]{{1,2},{3,4}}
dosth(ref a); //如果參數、引數只有其中一方宣告ref會引起錯誤
out關鍵字的作用則是傳出值,如:
public void assignValue(out int x, out int y){
x = 6; y = 10; //必須在method中宣告值
.........
}
int a; int b; //未賦予初始值
assignValue(out a, out b); //此時a = 6, b = 10
不過用法雖然多樣化了,但似乎連Visual Studio Team也不鼓勵ref、out的使用
畢竟若設計師不熟悉用法則容易出錯
一般是建議找替代方法來達成目標
struct的使用可以參考MSDN上的說明-使用結構
使用上有無法繼承與多型的限制,但在僅用來儲存field時會有較class更好的效能
其記憶體配置也是位在stack
所以指派的時候也是使用複製,等同於創造出新的struct
注意這點以避免疏失
而struct作為參數傳遞時,可考慮使用ref,以優化性能(當然這時候要注意值的變化)
C#的class有時候並不提供擴展,如第三方的類別等
要封裝類別只要在class宣告前加入sealed關鍵字,如:sealed class ap{...}
如果打算擴展這些類別,C#提供如下作法:
static class secondAp{
public static string getAns(this ap apobj, double fi1){...}
}
擴張方法必須是存在於靜態類別中的靜態方法
this ap 指定擴充ap類別
在method中也同樣是以複製的形式傳遞
也就是method中作的變動不會影響到原本的實值型別物件
不過若要改變傳遞的形式則可以使用 ref、out 兩個關鍵字
ref的用法為宣告使用call by reference
如:public void swap(ref int x, ref int y){ ... //code for swap x&y }
使用method時亦用ref,如:
int a = 1; int b = 2;
swap(ref a, ref b);
如此一來a與b的值就會在method呼叫過後改變了
C#在配置物件(參考型別資料)時亦隱含了ref的宣告
所以省略不寫也沒關係
但若明白的了ref宣告
則必須在參數、引述的地方都宣告,否則會引起編譯錯誤,如:
public void dosth(ref int[,] intary){ .... }
int[,] a = new int[]{{1,2},{3,4}}
dosth(ref a); //如果參數、引數只有其中一方宣告ref會引起錯誤
out關鍵字的作用則是傳出值,如:
public void assignValue(out int x, out int y){
x = 6; y = 10; //必須在method中宣告值
.........
}
int a; int b; //未賦予初始值
assignValue(out a, out b); //此時a = 6, b = 10
不過用法雖然多樣化了,但似乎連Visual Studio Team也不鼓勵ref、out的使用
畢竟若設計師不熟悉用法則容易出錯
一般是建議找替代方法來達成目標
struct的使用可以參考MSDN上的說明-使用結構
使用上有無法繼承與多型的限制,但在僅用來儲存field時會有較class更好的效能
其記憶體配置也是位在stack
所以指派的時候也是使用複製,等同於創造出新的struct
注意這點以避免疏失
而struct作為參數傳遞時,可考慮使用ref,以優化性能(當然這時候要注意值的變化)
C#的class有時候並不提供擴展,如第三方的類別等
要封裝類別只要在class宣告前加入sealed關鍵字,如:sealed class ap{...}
如果打算擴展這些類別,C#提供如下作法:
static class secondAp{
public static string getAns(this ap apobj, double fi1){...}
}
擴張方法必須是存在於靜態類別中的靜態方法
this ap 指定擴充ap類別
訂閱:
文章 (Atom)