程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> (譯)C#參數傳遞

(譯)C#參數傳遞

編輯:C#入門知識

前言

菜鳥去重復之Sql的問題還沒有得到滿意的答案。如果哪位大哥有相關的資料解釋,能夠分享給我,那就太謝謝了。

接觸C#一年了,感覺很多東西還是很模糊,像C#中的委托和事件

有些東西看多了不用也還是不會。還有些東西用多了不想也還是不精。

這次發現一篇解除我對於C#裡面參數傳遞困惑的詳細條例文章,忍不住翻譯留存以備回顧。

英文好的可以直接點此處看原文了。MSDN相關解釋鏈接在此處。

前奏:引用類型

在C#中有兩種常用的類型:和。他們表現不同,很多人在使用他們的時候都感到了困惑,這裡簡單解釋下他們的區別:

引用類型指

StringBuilder sb =  StringBuilder();

這裡我們定義了一個變量sb,創建一個新的StringBuilder對象,並把這個對象的引用賦給sb。sb實際存儲的值不是該對象,只是它的引用。

之間的賦值只是簡單地將其表達式或者變量賦給對應的變量。再看如下代碼:

StringBuilder first = =

這裡我們定義了一個變量first,創建了一個新的StringBuilder對象,並把這個對象的引用賦給first。然後我們將first賦給second。

這意味著他們都指向了同一個對象。如果我們通過使用first.Append的方式修改該對象的內容,second也同樣變化了。如下:

StringBuilder first = =

雖然會這樣,但他們仍然應該被看作相互獨立的變量。修改first指向一個完全不同的對象(或者直接將null賦給它)完全不會影響second。

StringBuilder first = ==  StringBuilder(
Console.WriteLine(second); 

前奏:值類型

在變量與真實數據之間有個間接層,卻不是。值類型變量直接存儲其數據。

之間賦值是將其值拷貝一份然後賦給對應的變量。下面用一個結構類型來解釋下:

  

IntHolder是個結構體的,它包含一個單獨的整型i。對其賦值將會拷貝,如下所示:

IntHolder first = = == 

這裡second.i值為5是因為當second=first時second.i保存了first.i的拷貝。自此,second是與first相互獨立的。

所以即使後來first.i=6,second.i依然不變。

 

:很多類型(例如string)是,但表現的卻像是。這些是,就是這些類型的實例一旦創建就不能再改變。

的對象的引用時,

 

 用一個可變的引用類型對比(例如ArrayList)加深大家理解。

如果一個方法的返回值為保存在變量中的一個ArrayList類型的引用,在方法內部並沒有創建新的實例直接使用,

而是對一個已有的實例進行增加等一些操作,其它人員卻不知道,這就可能出現問題。

之前說過了,大家千萬不要被其表面迷惑,理解其實質,才能更好地運用。

測試你的理解

如果之前的IntHolder不是結構類型而是類,那輸出的結果是多少呢?如果你不理解為什麼是6,那估計是我翻譯的有問題,

或者我翻譯得不夠清楚,實在罪過。如果您有好的建議,請告知我,不勝感激。

這裡再次奉上原文鏈接,以備有人實在看不下去我過爛的翻譯。

間奏:不同類型的參數

在C#中有四種不同類型的參數:,,,。

你可以同時使用值類型和引用類型參數。

當你使用這些參數的時候,你應該在腦海裡對“值類型”和“引用類型”有非常清晰的認識。

這樣不管是在使用它們還是與它們相關的類型的時候,你都會感覺非常輕松。

值類型參數

C#中默認參數是,這意味著在方法成員聲明時會為其變量會創建一份拷貝,它就是你在方法內部調用指定的變量的初始值。

如果你改變這個值,不會對調用中傳的值源造成任何影響。看下代碼:

= = ==);

y的值沒有改變只是因為x被賦null。無論如何,請一定記住引用類型變量存儲的是一個引用——如果兩個引用指向同一個對象,

那麼改變對象的內容,通過這兩個引用獲取到的對象也會發生改變。例如:

= 

在調用Foo(y)之後,y指向的值變為“hello world”,在Foo方法內部對引用變量x調用Append拼接“ world”字符實現了效果。

這裡我們再來看下傳遞如何。正如之前提到的,值類型的值就是它本身。

使用之前的結構類型IntHolder,我們寫一些與之前類似的代碼來測試下:

== =

當Foo被調用時,x是個struct類型,並且它的i為5。之後將10賦給了i。

Foo一點都不知道y。當這個方法執行結束,y還是和它之前一模一樣。

我們之前展示了一些關於引用類型作為傳遞的例子。

那麼你應該明白當IntHolder聲明為類時會發生什麼。你應該清楚為什麼y.i會因此變成10。

引用類型參數

使用的時候不傳遞其實際值,只是使用變量本身。也就是說不會創建一個新的拷貝,而是使用相同的存儲地址。

因此在方法成員中的值類型與引用類型一直都是一樣的。

使用在聲明和調用的時候需要使用ref關鍵字——這意味著你要使用將會看起來清晰明確。

我們再來改動下之前的例子測試下:

 Foo (= = ==); 

這裡,因為將y的引用傳遞給x而不是它的值,所以對x進行的操作相當於對y進行操作一樣。在上例中y最後為null。

請將這個結果與上面的沒有使用ref關鍵字的例子結果進行比較。

現在,讓我們測試下之前使用結構作為參數的例子加上ref關鍵字後會發生什麼:

 Foo (== =

這兩個變量共用一個內存地址,因此改變x時y也會發生改變。所以y.i是10。

注意:通過默認的值類型參數方式傳遞引用類型變量與通過引用類型參數方式傳遞值類型變量

       有什麼區別呢?

你可能已經注意到了在最後一個例子中,將一個結構類型通過引用方式傳遞,與通過值類型方式傳遞一個類有同樣的結果。

但這不意味他們是一樣的。好吧,還是讓我們通過下面的代碼加深下理解:

 Foo (???= = =??? y);

假設IntHolder是個結構類型(即值類型),方法參數為引用類型(即將???替換為ref),

執行代碼,y最後將會指向一個new IntHolder,y.i會因此變為0。

假設IntHolder是個類(即引用類型),方法參數為值類型(即將???去掉),

執行代碼,y的指向不會改變,y.i仍為5。

在調用函數前y與x確實指向同一個對象。理解C#參數傳遞中的這個區別絕對是相當關鍵的。

這也是為什麼原作者認為當人們談及對象默認引用傳遞的時候會非常困惑,其實正確的說法應該是引用類型默認值傳遞。

Out類型參數

和很像,它不會創建新的內存地址,而是共享內存地址。

使用的方法在聲明和調用的時候需要加上關鍵字Out。這樣也會使代碼看起來清晰。

雖然與非常相似,但它們還是有區別的。Out類型與引用類型的不同之處:

1.方法調用時傳遞的變量不用事先賦值。如果方法調用正常結束,即可認為該變量後來被賦值了(這樣,你就可以直接讀取它的值了)。

2.該參數傳遞時被看作沒有初始化(也就是說你在讀取它之前,必須先給它賦值)。

3.在方法結束前必須對這個參數進行賦值,否則編譯器會報錯。

下面展示一個例子進行加深大家理解,使用的是一個int型作為參數

int是值類型,如果你已經理解了引用類型,相信你也會知道引用類型作為參數會發生什麼:

 Foo ( 
    x = 
     a =

Foo (
Console.WriteLine (y); 

參數數組(params)

允許傳遞給一個方法一組數據。定義包含的方法時必須加上關鍵字params,調用該方法的時候卻不必加上這個關鍵字。

必須放在方法參數的最後,並且只能是一維數組。

當使用這類方法時,調用中只要參數與定義時參數數組類型兼容,就能夠傳遞。

由於的這種使用方式,所以當你想傳遞一個單獨的數組,它的效果就像是值類型參數傳遞。例如:

 ShowNumbers (  ( x + [] x = {, , , 
  
 

第一次調用時,x是一個整型數組,效果等同於將它(引用)作為傳遞。

第二次調用時,將會創建一個包含4,5的整型數組,並將它的引用傳遞(仍然是)。

尾奏:總結

翻譯出來總是容易使文章讀起來拗口難理解。第一次翻譯技術文章,我肯定也避免不了。只求能夠對大家及我有所幫助。

程序員,英語很重要。

如果您英文比較好的話,我還是建議您讀一下原文。

如果本文中有疏漏或者理解錯誤的地方,還請指出,不勝感激。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved