将引用类型和值类型作为参数传递给方法

时间:2016-07-13 06:41:50

标签: c#

整天都在脑子里想着这种混乱。 在传递给方法的引用和值类型之间我非常困惑。

假设我有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”吗?

请帮我澄清这个简单的疑问。

3 个答案:

答案 0 :(得分:4)

Reference TypeValue Type旁边,有Mutable TypeImmutable 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#中,发送给方法的所有参数都传递按值,除非它们使用refout关键字传递。

这包括值类型,引用类型,可变和不可变类型的参数。

引用类型参数传递给方法时,实际发生的是参数的引用按值传递

这意味着该方法实际上将 新引用 保存到传递给它的参数中。
因此,当使用方法外部的引用时,也会反映对该参数状态的任何更改 但是,在为方法内部的引用分配新值时,它不会反映在方法外部的引用上。

要获得更好,更广泛的解释,请阅读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);
}

You can see for yourself on this fiddle.