如果我将流作为传递值类型参数方法传递给方法,我需要将流(c#)重置回开始吗?

本文关键字:方法 开始 类型参数 如果 | 更新日期: 2023-09-27 17:52:16

我在网上看到过几个例子,我必须通过

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

但是,如果我将流作为

传递给方法
public static bool ValidateStreamLine(Stream stream)

我还需要重置流吗?

请理解,通常情况下,如果我传入int, string, float或任何其他通用变量类型

public static bool ValidateInt(int i)

int I的值不会改变。

传递值方法对流的反应有什么本质上的不同吗?

如果我将流作为传递值类型参数方法传递给方法,我需要将流(c#)重置回开始吗?

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

这里需要理解的重要一点是,如果实参类型是引用类型或值类型,那么通过value传递的实参的行为是完全不同的。这就是你似乎感到困惑的地方。

要理解它是如何工作的,请确保您清楚以下内容:

  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!