2016-06-28 23 views
1

我已經看到互聯網上的一些示例聲明,我必須將流重置爲我是否需要將流(C#)重置爲開始,如果我將流傳遞到方法中作爲傳遞值類型參數方法

stream.Seek(0, SeekOrigin.Begin); 

然而,如果我通過了流進作爲

public static bool ValidateStreamLine(Stream stream) 

的方法我必須仍然重置流?

明白上通常情況下,如果我在整型,字符串,浮子或任何其他一般變量類型傳遞作爲

public static bool ValidateInt(int i) 

INT的我不會改變的值。

這是傳遞價值法的性質與流如何反應的性質有什麼區別嗎?

+0

是。流是訪問方法,而不是內容。而且無論如何你都無法通過它來傳遞它,它是一個引用類型 –

+0

@PanagiotisKanavos這是否意味着我可以在ValidateStreamLine方法中進行重置,它也可以工作? –

+1

@PanagiotisKanavos我很挑剔,但它是通過值傳遞的,它是一個通過值傳遞的引用類型 –

回答

1

您似乎誤解了C#中參數傳遞的方式。默認情況下,所有參數均以C#中的傳遞。爲了通過參考來傳遞它們,您需要使用特殊關鍵字:refout當參數用作給定方法的第二個輸出時,通常使用後者。 (例如見int.TryPase)。

這裏要理解的重要一點是,如果參數的類型是引用類型或值類型,那麼通過值傳遞的參數表現得相當不同。這是你似乎困惑的地方。

理解它是如何工作的,請確保您明確以下幾點:

  1. 變量持有
  2. 值,其類型是值類型變量是該值類型的實例本身

    int i = 1 // i holds the value 1 
    
  3. 值,其類型的變量的參考類型不是所述類型的實例。值爲該實例所在的內存地址

    string s = "Hello!" // s does not hold "Hello!" it holds a number that points to a place in memory where the string "Hello!" lives. 
    

所以,現在我們都清楚這一點,當你按值傳遞參數(C#的默認值)會發生什麼?會發生什麼是變量的副本,副本傳遞給方法

如果類型是引用類型,那麼真正複製並傳遞給方法的是存儲在變量中的值。那是什麼?變量引用的對象所在的內存地址。所以你看看會發生什麼?兩個原始變量和複製的可變都指向同一個對象

public class Foo 
{ 
    var frobbed = false; 
    public bool Frobbed { get { return frobbed; } } 
    public void Frob() { frobbed = true; } 
} 

void Frob(Foo foo) { foo.Frob(); } 
var myFoo = new Foo(); 
Frob(myFoo); 
Console.WriteLine(myFoo.Frobbed); //Outputs True! Why? Because myFoo and foo both point to the same object! The value of both variables (memory address) is the same!  

如果類型爲值類型,值類型的值本身被拷貝並送交方法,所以沒有方法可以修改存儲在原始變量中的值類型。

public void Increment(int i) { i = i + 1; } 

var myInt = 1; 
Increment(myInt); 
Console.WriteLine(myInt); //Outputs 1, not 2. Why? i holds its own copy of 1, it knows nothing about the copy of 1 stored in myInt. 

當您通過引用傳遞參數時,事情會改變。現在,傳遞給該方法的參數不是副本,而是其原始變量本身。一個邏輯問題如下:這實際上是否改變了參考類型的行爲方式?答案是肯定的,相當多:

public void ByValueCall(string s) 
{ 
    s = "Goodbye"; 
} 

public void ByReferenceCall(ref string s) 
{ 
    s = "Goodbye"; 
} 

var myString = "Hello!"; 
Console.WriteLine(ByValueCall(myString)); //outputs "Hello!" 
Console.WriteLine(ByValueCall(myString)); //outputs "Goodbye!" 

此行爲與值類型也相同。這裏發生了什麼?

當您通過值傳遞參數時,該方法獲取變量的副本;因此爲該參數分配一個新值實際上只是爲該副本分配一個新值;在調用網站的原始變量不關心你改變它的拷貝的值,不管它是一個值類型還是一個引用類型。它將繼續保持它始終擁有的價值。

當通過引用傳遞參數時,您不傳遞副本,而是傳遞變量本身。在這種情況下,爲變量分配一個新的值將保留在調用點。一個典型的例子就是下面的交換方法:

public void Swap(ref int a, ref int b) 
{ 
    var temp = a; 
    a = b; 
    b = temp; 
} 

var i1 = 1; 
var i2 = 2; 
Swap(ref i1, ref i2); 
var b = i1 == 2; //true 
b = i2 == 1; //true 

所以經過這一切,你應該明白爲什麼下面的行爲方式是這樣:

public ResetStream(Stream stream) 
{ 
    stream.Seek(0, SeekOrigin.Begin); 
} 

var myStream = new ... 
myStream.Read(bytes, 0, 1024); 
ResetStream(myStream); 
var isAtOrigin = myStream.Position == 0; //Returns true! 
+0

@BenKnoble大聲笑,我完全忘了那個。修正了,謝謝。 – InBetween

+0

感謝您的解釋:)有一個額外的問題。除流,字符串類型外,其他類型的行爲類似?有沒有完整的清單? –

+0

@SimonLoh絕大多數是參考類型。規則很簡單:*結構*是*值類型*和a *類*是*引用類型*。如果您不確定,只需檢查類型的定義。 – InBetween

相關問題