首页 新闻 会员 周边

C#参数的问题,这个要怎么解释呢

0
悬赏园豆:50 [已解决问题] 解决于 2014-06-23 11:35
代码如下:

    public class Foo
    {
        public string F1 { get;set;}
        public int F2 { get; set; }

    }
    class Program
    {
        static void Main(string[] args)
        {
            Foo foo = new Foo();
            foo.F1 = "A";
            foo.F2 = 1;  
            Test(foo);
            Console.WriteLine("F1={0},F2={1}", foo.F1, foo.F2);
        }
        private static void Test(Foo foo)
        {
            Foo tmp = new Foo();
            tmp.F1 = "F1";
            tmp.F2 = 20;
            foo = tmp;
        }
    }     

代码的输出是什么呢???

 

 

 

 

 

输入结果:

F1=A,F2=1

为什么输出不是F1=F1,F2=20呢?

山寨程序员的主页 山寨程序员 | 初学一级 | 园豆:71
提问于:2014-06-21 20:55
< >
分享
最佳答案
2

楼上已经说的很好了,我补充一下。

在进入方法 Test 之前,变量 foo 的地址和值分别如下图所示:

 

在进入方法 Test 之后并且实例化局部变量 tmp 之前,变量 foo 的地址和值分别如下图所示:

 

可以看到变量 foo 的地址已经变了,而值尚未改变,局部变量 tmp 也已经初始化了,只是尚未赋值,接着再往下看。

当实例化 tmp 后各变量的值如下所示:

 

这一步除了实例化 tmp 外没有其他操作。

然后再看 tmp 赋值给 foo 后是什么情况:

foo 地址没变,值变成 tmp 的值了。

接着跳出 Test,看看又是神马情况:

 

额,foo 的地址和值都变成进入 Test 之前的了,也就是说我们在 Test 里对 foo 地址和值所做的改变都无效,对于输出也就不难理解了。

这个和 C++ 里对指针的操作是一样的,在一个方法里要对指针引用做修改,只需要传递指针进来就够了,但如果要对指针本身做修改就需要传递指针的地址(即指针的指针)进来才行了,因为指针地址本身也只是一个值类型的整数。

以上是我的理解,不正确的还请多包涵。

收获园豆:20
platobeing | 菜鸟二级 |园豆:222 | 2014-06-22 18:40
其他回答(3)
0

C#函数的参数如果不加ref,out这样的修饰符显式申明参数是通过引用传递外,默认都是值传递.

你修改传递过来的值,也只能作用于传递过来的这个值。

如果你修改传递过来的引用,就可以作用到原来的值了。

收获园豆:15
飞来飞去 | 园豆:2057 (老鸟四级) | 2014-06-21 21:21

这个算是c#的一个坑吗?

见到过一个swap的写法如下:

        public static void Swap(Foo a, Foo b)
        {
            Foo tmp = a;
            a = b;
            b = tmp;
        }

写的人认为Foo是按引用传递,在子函数里面交换了形参,实参也交换了。这样解释是否更合理:对于不加ref或out的参数,函数调用中发生的数据传送是单向的。 即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。 因此在函数调用过程中,形参的值发生改变,而实参的值不会变化。

最近看swift中的的参数传值,有三种传参方式let var inout,就明确避免了这类问题。

支持(0) 反对(0) 山寨程序员 | 园豆:71 (初学一级) | 2014-06-21 21:59
0

因为在方法里foo变量引用的实例变了,但是在Main里的实例还是原来那个

如果你在方法里不new一个新的实例,而是直接更改foo的属性F1、F2的值,那么就可以看到输出的值为F1=F1,F2=20

收获园豆:5
诶碧司 | 园豆:1912 (小虾三级) | 2014-06-21 21:54
0

首先,参数foo必然是引用传递,因为C#除了明确的值类型,其他类型都是引用传递。

第二,你在test中是对参数值进行修改,C#中,只要不表明ref/out,则对参数值的修改将只在函数内部有效。你在test中new了一个新的tmp,然后将其值赋给参数foo,这就是对foo这个参数的修改。

而Swap函数中并没有对参数进行修改,而是对引用类型内部的值进行修改,这时就会影响这个引用的原始数据。

其实这个和C的指针是一样的,函数参数是指针还是指针的指针,ref相当于指针的指针

收获园豆:10
hailants | 园豆:750 (小虾三级) | 2014-06-22 16:46
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册