如果我将流作为Pass Value-Type Parameter方法传递给方法,是否需要将流(C#)重置为开头

时间:2016-06-28 12:45:10

标签: c#

我在互联网上看过几个例子,说我必须通过

重置流
stream.Seek(0, SeekOrigin.Begin);

但是,如果我将流传递给方法

public static bool ValidateStreamLine(Stream stream)

我是否还要重置流?

了解通常情况下,如果我将int,string,float或任何其他常规变量类型传递为

public static bool ValidateInt(int i)

int i的值不会改变。

传递值方法的性质与方法对流的反应有何不同?

1 个答案:

答案 0 :(得分:1)

您似乎误解了如何在C#中传递参数。默认情况下,所有参数都由C#中的 value 传递。要通过引用传递它们,您需要使用特殊关键字:refout当参数用作给定的第二个输出时,通常使用后者方法。 (例如,请参阅int.TryPase。)

这里要理解的重要一点是,如果参数的类型是引用类型或值类型,则通过值传递的参数的行为会非常不同。这就是你似乎感到困惑的地方。

要了解这一切是如何运作的,请确保您清楚以下内容:

  1. 变量包含
  2. 类型为值类型的变量的是值类型&n;实例本身

    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.
    
  4. 那么,既然我们已经清楚了,那么当您按值传递参数时会发生什么(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!