我在互联网上看过几个例子,说我必须通过
重置流stream.Seek(0, SeekOrigin.Begin);
但是,如果我将流传递给方法
public static bool ValidateStreamLine(Stream stream)
我是否还要重置流?
了解通常情况下,如果我将int,string,float或任何其他常规变量类型传递为
public static bool ValidateInt(int i)
int i的值不会改变。
传递值方法的性质与方法对流的反应有何不同?
答案 0 :(得分:1)
您似乎误解了如何在C#中传递参数。默认情况下,所有参数都由C#中的 value 传递。要通过引用传递它们,您需要使用特殊关键字:ref
或out
当参数用作给定的第二个输出时,通常使用后者方法。 (例如,请参阅int.TryPase
。)
这里要理解的重要一点是,如果参数的类型是引用类型或值类型,则通过值传递的参数的行为会非常不同。这就是你似乎感到困惑的地方。
要了解这一切是如何运作的,请确保您清楚以下内容:
类型为值类型的变量的值,是值类型&n;实例本身:
int i = 1 // i holds the value 1
类型为引用类型的变量的值不是所述类型的实例。该值是该实例所在的内存地址。
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!