我无法理解参考资料!

Vitzzviperzz.

众所周知的成员
加入
2017年1月16日
消息
75
地点
英国
编程经验
1-3
你好,

所以我正如我一直在努力更复杂的C#主题,我似乎无法像往常一样轻松掌握一些东西。

其中一个主题是参考!

我想我可能已经问过这个问题,但没有妥善问过这个问题。

有人可以解释他们用一些代码解释的用途吗?

我看过这两片代码,但我只是无法理解正在发生的事情。

C#:
public void ModifyAnIntAndButton(ref int value, ref Button button) 
{    

int i = value;    
i *= 5;    
value = i - 3;    
button = button1; 

}

private void button2_Click(object sender, EventArgs e) 
{  
 
 int q = 100;    
Button b = button1;   
 ModifyAnIntAndButton(ref q, ref b);   
Console.WriteLine("q = {0}, b.Text = {1}", q, b.Text); 

}

C#:
static void addOneToRefParam ( ref int i )  
{  

i = i + 1;  
Console.WriteLine ( "i is : " + i ) ; 

}

test = 20 ; 

addOneToRefParam(ref test); 
Console.WriteLine ( "test is : " + test ) ;

我是:21
测试是:21

如何?
 

jmplhinney.

C#论坛主持人
工作人员
加入
2011年4月23日
消息
3,732
地点
悉尼,澳大利亚
编程经验
10+
你并没有真正询问一般的引用,而是通过引用传递方法参数,这只是整个参考论的一部分。可以通过专注于结果而不是基础机制来分离来讨论传递方法参数,这是我将在这里做的。

方法参数默认情况下通过值传递,但可以指定为通过引用传递。您可以使用“out”或'ref'关键字声明方法参数作为通过引用传递。默认情况下,方法参数仅用于将数据传递给一种方法。如果使用“out”声明参数,则该参数仅用于将数据传递出该方法。如果声明使用“ref”的方法,那么该参数可用于将数据传递到方法中和/或从方法中传递。这真的就是这样。看看这个例子:
namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            int valVariable = 1;
            int outVariable = 2;
            int refVariable = 3;

            Console.WriteLine("valVariable = {0}; outVariable = {1}; refVariable = {2}", valVariable, outVariable, refVariable);

            ExampleMethod(valVariable, out outVariable, ref refVariable);

            Console.WriteLine("valVariable = {0}; outVariable = {1}; refVariable = {2}", valVariable, outVariable, refVariable);
            Console.ReadLine();
        }

        private static void ExampleMethod(int valParameter, out int outParameter, ref int refParameter)
        {
            //Console.WriteLine("valParameter = {0}; outParameter = {1}; refParameter = {2}", valParameter, outParameter, refParameter);
            Console.WriteLine("valParameter = {0}; refParameter = {1}", valParameter, refParameter);

            valParameter = 100;
            outParameter = 200;
            refParameter = 300;

            Console.WriteLine("valParameter = {0}; outParameter = {1}; refParameter = {2}", valParameter, outParameter, refParameter);
        }
    }
}

该代码创建三个变量,调用该方法并将变量作为参数传递,并在该方法内设置三个参数。

第一个要注意的是每个控制台.Writeline陈述以及一个已评论的事实。如果您取消注释该行,您将看到它会生成编译错误。那是因为,正如我所说,声明'out'的参数仅用于传递数据,使得编译器甚至不会让您尝试使用它的值,直到您设置它。如果您未在方法中某处设置“out”参数,那么它也会生成编译错误。

如果您运行该代码并检查输出,则会看到第一行输出三个变量的初始值,就像您期望的那样。第二行输出传递给该方法的值,除了在舞台中不能使用的“out”参数之外。第三行输出您刚刚分配给参数的值,就像您期望的那样。第四行是一个有趣的线。

第四行表明,即使在方法内修改了相应的参数,也仍然保持不变的第一变量的值。通过引用传递的第二和第三变量的值已经改变,反映了对方法内的相应参数所做的更改。这就是我想说的。在方法内设置一个参数时,才会影响原始变量,如果该参数通过引用传递。

所以,你真正要记住的就是:

1.如果要将数据传递到方法中,并且不希望对参数的更改以影响原始变量,则按值传递参数,这是默认值,并将在绝大多数情况下使用。
2.如果要将数据传递出一种方法,则只声明参数'out'。在这种情况下,将忽略您传递的任何原始值。一个完美的例子是任何troparse方法。
3.如果要选择将数据传递到方法,并且可选地返回新值,请声明参数“REF”。
 

Vitzzviperzz.

众所周知的成员
加入
2017年1月16日
消息
75
地点
英国
编程经验
1-3
你并没有真正询问一般的引用,而是通过引用传递方法参数,这只是整个参考论的一部分。可以通过专注于结果而不是基础机制来分离来讨论传递方法参数,这是我将在这里做的。

方法参数默认情况下通过值传递,但可以指定为通过引用传递。您可以使用“out”或'ref'关键字声明方法参数作为通过引用传递。默认情况下,方法参数仅用于将数据传递给一种方法。如果使用“out”声明参数,则该参数仅用于将数据传递出该方法。如果声明使用“ref”的方法,那么该参数可用于将数据传递到方法中和/或从方法中传递。这真的就是这样。看看这个例子:
namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            int valVariable = 1;
            int outVariable = 2;
            int refVariable = 3;

            Console.WriteLine("valVariable = {0}; outVariable = {1}; refVariable = {2}", valVariable, outVariable, refVariable);

            ExampleMethod(valVariable, out outVariable, ref refVariable);

            Console.WriteLine("valVariable = {0}; outVariable = {1}; refVariable = {2}", valVariable, outVariable, refVariable);
            Console.ReadLine();
        }

        private static void ExampleMethod(int valParameter, out int outParameter, ref int refParameter)
        {
            //Console.WriteLine("valParameter = {0}; outParameter = {1}; refParameter = {2}", valParameter, outParameter, refParameter);
            Console.WriteLine("valParameter = {0}; refParameter = {1}", valParameter, refParameter);

            valParameter = 100;
            outParameter = 200;
            refParameter = 300;

            Console.WriteLine("valParameter = {0}; outParameter = {1}; refParameter = {2}", valParameter, outParameter, refParameter);
        }
    }
}

该代码创建三个变量,调用该方法并将变量作为参数传递,并在该方法内设置三个参数。

第一个要注意的是每个控制台.Writeline陈述以及一个已评论的事实。如果您取消注释该行,您将看到它会生成编译错误。那是因为,正如我所说,声明'out'的参数仅用于传递数据,使得编译器甚至不会让您尝试使用它的值,直到您设置它。如果您未在方法中某处设置“out”参数,那么它也会生成编译错误。

如果您运行该代码并检查输出,则会看到第一行输出三个变量的初始值,就像您期望的那样。第二行输出传递给该方法的值,除了在舞台中不能使用的“out”参数之外。第三行输出您刚刚分配给参数的值,就像您期望的那样。第四行是一个有趣的线。

第四行表明,即使在方法内修改了相应的参数,也仍然保持不变的第一变量的值。通过引用传递的第二和第三变量的值已经改变,反映了对方法内的相应参数所做的更改。这就是我想说的。在方法内设置一个参数时,才会影响原始变量,如果该参数通过引用传递。

所以,你真正要记住的就是:

1.如果要将数据传递到方法中,并且不希望对参数的更改以影响原始变量,则按值传递参数,这是默认值,并将在绝大多数情况下使用。
2.如果要将数据传递出一种方法,则只声明参数'out'。在这种情况下,将忽略您传递的任何原始值。一个完美的例子是任何troparse方法。
3.如果要选择将数据传递到方法,并且可选地返回新值,请声明参数“REF”。

嘿,谢谢你的回复。

我认为这有助于清除它更多。

我只需要继续为他们工作,直到它终于点击。
 

罗丹

活跃的成员
加入
2015年4月7日
消息
41
编程经验
10+
如果你仍然有点麻烦,请尝试这个类比。

你有一个鸡蛋的鸡蛋,如果你六个出来,你想知道你会有多少。你计算它们并将数字写下来然后在纸上做数学 - 这就像通过价值一样。
如果你抓住纸箱并拿出六个鸡蛋,就像通过引用一样。您最终以相同的数字结束,但按值执行此操作不会改变纸箱中的鸡蛋数。

所以按价值(默认)就像写下数字并在纸上做,而不是触摸纸箱。
C#:
myEggCount = SubtractEggsFromCarton(carton);

private int SubtractEggsFromCarton(int eggsInCarton)
{
    eggsInCarton -= 6
    return eggsInCarton;
}
// myEggCount = 6 carton = 12
但是,通过引用就像用纸浆中的鸡蛋出来。
C#:
myEggCount = SubtractEggsFromCarton(carton);

private int SubtractEggsFromCarton(ref int eggsInCarton)
{
    eggsInCarton -= 6
    return eggsInCarton;
}

// myEggCount = 6 carton = 6

虽然以不同的方式命名,但在通过引用传递时,蛋蛋白和纸箱是相同的变量。为蛋蛋白完成的东西实际上是为纸箱做的
 

Vitzzviperzz.

众所周知的成员
加入
2017年1月16日
消息
75
地点
英国
编程经验
1-3
如果你仍然有点麻烦,请尝试这个类比。

你有一个鸡蛋的鸡蛋,如果你六个出来,你想知道你会有多少。你计算它们并将数字写下来然后在纸上做数学 - 这就像通过价值一样。
如果你抓住纸箱并拿出六个鸡蛋,就像通过引用一样。您最终以相同的数字结束,但按值执行此操作不会改变纸箱中的鸡蛋数。

所以按价值(默认)就像写下数字并在纸上做,而不是触摸纸箱。
C#:
myEggCount = SubtractEggsFromCarton(carton);

private int SubtractEggsFromCarton(int eggsInCarton)
{
    eggsInCarton -= 6
    return eggsInCarton;
}
// myEggCount = 6 carton = 12
但是,通过引用就像用纸浆中的鸡蛋出来。
C#:
myEggCount = SubtractEggsFromCarton(carton);

private int SubtractEggsFromCarton(ref int eggsInCarton)
{
    eggsInCarton -= 6
    return eggsInCarton;
}

// myEggCount = 6 carton = 6

虽然以不同的方式命名,但在通过引用传递时,蛋蛋白和纸箱是相同的变量。为蛋蛋白完成的东西实际上是为纸箱做的

嘿,这是一个非常有趣的方式来看它。解释帮助我了解它更实际上 - 谢谢你。

迟到回复,因为我正在做其他事情,但谢谢。
 

罗丹

活跃的成员
加入
2015年4月7日
消息
41
编程经验
10+
嘿,这是一个非常有趣的方式来看它。解释帮助我了解它更实际上 - 谢谢你。

迟到回复,因为我正在做其他事情,但谢谢。

没问题。在两种传递方法中实际发生了什么:

按value - 将提供的变量的值复制到局部变量中
通过引用 - 将本地变量的内存地址分配给提供的变量的内存地址,以便您只需使用不同的名称以获取相同的内存位置。

在C / C ++中,他们将此称为使用指针。指针是一种特殊类型的变量,只能保存其他变量的地址。有很多技巧你可以使用指针,但如果你不完全明白你在做什么,你就可以很快让自己陷入困境。我几十年前尝试了,虽然我明白了什么指针,但是当它开始指向指针等时,刚刚让事情搞砸了。我发现更高级别的语言更容易保持控制。

那么为什么你会使用参考而不是值?好吧,一个原因是速度。如果您通过大量数据(阵列,列表,类别等)而不是简单的int或其他东西,那么它可能需要很长一段时间(在计算机术语中)将所有数据复制到本地变量中。如果您通过引用通过,那么您就不会复制任何内容,您只需发送真正快速的32/64位地址。您必须完全清楚您对本地变量做的任何事情实际上都在传递的变量上完成。此外,如果通过REF传递然后分配给局部变量,那么您可能刚刚通过价值,因为它会花费只需复制所有内容即可。

大多数按价值的时间都是您所需要的。
 

约翰

C#论坛主持人
工作人员
加入
2011年4月23日
消息
1,161
地点
挪威
编程经验
10+
Rhodan said:
那么为什么你会使用参考而不是值?好吧,一个原因是速度。如果您通过大量数据(阵列,列表,类别等)而不是简单的int或其他东西,那么它可能需要很长一段时间(在计算机术语中)将所有数据复制到本地变量中。如果您通过引用通过,那么您就不会复制任何内容,您只需发送真正快速的32/64位地址。您必须完全清楚您对本地变量做的任何事情实际上都在传递的变量上完成。此外,如果通过REF传递然后分配给局部变量,那么您可能刚刚通过价值,因为它会花费只需复制所有内容即可。
价值类型和参考类型是一种不同的讨论。您提到的对象是引用类型,并且始终通过引用,但参考本身也可以作为值或引用传递。这几乎是"pointer to pointer" distress you had :) 例如,您拥有一个对象(a),具有一些其他对象类型(b)的属性,如果传递该属性的对象(即对象b),则接收方法可以修改该对象。无论是否通过价值或参考a传递A会看到对象B的更改。如果方法可以分配一个新对象(B#2),则差异是它不能,但通过引用传递,但它可以通过引用来分配新对象(B#2)。
一个抽象的例子:
    class A
    {
        public B Sample { get; set; }
    }

    class B
    {
        public int ID { get; set; }
    }

        static void ByValue(B input)
        {
            input.ID = 1;
            input = new B() { ID = 2 };
        }

        static void ByReference(ref B input)
        {
            input.ID = 1;
            input = new B() { ID = 2 };
        }

            B someB = new B();
            A someA = new A() { Sample = someB };            

            ByValue(someB);
            var same = (someA.Sample == someB); // true
            var value = someA.Sample.ID; // 1
            

            ByReference(ref someB);
            same = (someA.Sample == someB); // false, someB is now different object
            value = someA.Sample.ID; // 1
            var valueB = someB.ID; // 2
 
最佳 底部