整天都在脑子里想着这种混乱。 在传递给方法的引用和值类型之间我非常困惑。
假设我有2个类 A类和 B类,分别对应于参考和值类型。
public Class A
{
public static void main(string[] args)
{
String s = “hello”;
String w = Changestring(s);
String x = s;
}
private string Changestring(string s)
{
s += “Hi”;
return s;
}
}
public Class B
{
public static void main(string[] args)
{
int s = 99;
int w = Changeint(s);
int x = s;
}
private int Changeint(int s)
{
s += 30;
return s;
}
}
我很难将引用类型(字符串)和值类型(int)作为函数的参数传递。 当我运行这样的程序时,字符串的x(引用类型)本身是“hello”,值类型的x是99.由于它是引用类型,x应该是“HelloHi”而不是“hello”吗?
请帮我澄清这个简单的疑问。
答案 0 :(得分:4)
在Reference Type
和Value Type
旁边,有Mutable Type
和Immutable Type
。
Immutable
表示初始化后对象不能也不会被更改。因此,您的语句只生成新字符串,但不会修改原始字符串。
s + ="嗨&#34 ;;
hello
字符串对象仍为hello
。更改是s
分配了新对象helloHi
。
以string
为例,你很不幸。
尝试在示例中使用StringBuilder
等可变类型。
public class C
{
public static void Main(string[] args)
{
StringBuilder s = new StringBuilder("hello");
StringBuilder w = Changestring(s);
StringBuilder x = s;
}
private static StringBuilder Changestring(StringBuilder s)
{
s.Append("Hi");
return s;
}
}
答案 1 :(得分:2)
首先要知道,传递值不会更改初始变量值,其中通过引用传递也更改方法引用的初始变量值。
默认情况下int
被视为值类型,因此它按值传递。但是,String
甚至声明为类(引用类型),默认情况下它与sealed
修饰符不可变,因此被视为按值传递并添加新字符只是创建{{1}的新实例},而不是改变现有的。
通过添加String
关键字,您可以将int行为更改为传递引用:
ref
对于A类,您需要一个StringBuilder实例来完成" helloHi":
public Class B
{
public static void main(string[] args)
{
int s = 99;
int w = Changeint(s); // w has changed
int x = s; // s has also changed
}
private int Changeint(ref int s)
{
s += 30; // result = 129
return s;
}
}
CMIIW。
答案 2 :(得分:2)
在c#中,发送给方法的所有参数都传递按值,除非它们使用ref
或out
关键字传递。
这包括值类型,引用类型,可变和不可变类型的参数。
将引用类型参数传递给方法时,实际发生的是参数的引用按值传递 强>
这意味着该方法实际上将 新引用 保存到传递给它的参数中。
因此,当使用方法外部的引用时,也会反映对该参数状态的任何更改
但是,在为方法内部的引用分配新值时,它不会反映在方法外部的引用上。
要获得更好,更广泛的解释,请阅读Jon Skeet的Parameter passing in C#文章。
您无法使用任何不可变类型对此进行测试,因为根据定义,不可更改类型无法更改。
但是,您可以使用任何可变类型对此进行测试:
public static void Main()
{
var x = new List<int>();
x.Add(1);
Add(x, 2);
Console.WriteLine(x.Count.ToString()); // will print "2";
AddRef(ref x, 3);
Console.WriteLine(x.Count.ToString()); // will print "1";
Add3(x, 1, 2, 3 );
Console.WriteLine(x.Count.ToString()); // will also print "1";
Add3Ref(ref x, 1, 2, 3 );
Console.WriteLine(x.Count.ToString()); // will print "3";
}
static void Add(List<int> list, int value)
{
// adding an item to the list, thus chaning the state of the list.
// this will reflect on the list sent to the method,
// since a List is a reference type.
list.Add(value);
}
static void AddRef(ref List<int> list, int value)
{
list = new List<int>(); // same as the s += “Hi”; in the question
// Adding the value to the list.
// Note that this change will reflect on the list passed to the method,
// since it is passed using the ref keyword.
list.Add(value);
}
static void Add3(List<int> list, int value1, int value2, int value3)
{
list = new List<int>(); // same as the s += “Hi”; in the question
// these values are added to the new list.
// since the reference to the list was passed by value,
// it WILL NOT effect the list sent to the method.
list.Add(value1);
list.Add(value2);
list.Add(value3);
}
static void Add3Ref(ref List<int> list, int value1, int value2, int value3)
{
list = new List<int>(); // same as the s += “Hi”; in the question
// these values are added to the new list.
// since the list was passed by reference,
// it WILL effect the list sent to the method.
list.Add(value1);
list.Add(value2);
list.Add(value3);
}