通过引用传递vs通过值传递('数据别名'是C#中的问题?) [英] Pass by reference vs Pass by Value (is 'data aliasing' a problem in C#?)

查看:50
本文介绍了通过引用传递vs通过值传递('数据别名'是C#中的问题?)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这篇帖子最初是在C#Corner网站上,但是他们的服务器是

。我想看看这个小组是否可以回答。


我用C ++编程并且正在学习C#。


问题是:为什么有人会在C#中使用ref引用传递引用

关键字或外出对于方法参数中的对象

list,毕竟它出现在C#中,对于所有意图和

目的,总是传递引用,而不是真实的

对象(似乎是,像int这样的数据原语的例外,

不是''盒装'')。


来自C#Corner的海报回复,叫他Brian,为什么''ref''

需要写出一个简单的演示程序(见下文),
确实似乎反驳了上述情况,并指出除非你使用关键字ref,否则使用关键字ref。在你的方法参数中,你不能在方法内部更改传递给方法的

对象。


然而 - 这就是这个发布 - 似乎我找到了一个

的解决方法,这样即使使用按价值传递,你也可以确定
确实改变了传递的对象,在调用方法内部(当你使用
退出方法时),如果使用赋值运算符=并返回一个

的新对象(见下面的评论////)。我不认为C ++中已知的''b'是一个问题,因为''别名''在这里是一个问题。

" workaround" (如我错了请纠正我)。这个帖子真的是这个帖子的重点 - 当你在C#中传递价值时,你能否拥有'数据别名',

因为我们'总是处理参考文献,理论上它是b / b
应该是安全的吗?作为一种编码风格,下面我的

''变通方法'还有其他潜在问题吗?


有何评论?为什么我们毕竟需要参考?


Fran


//启动控制台C#程序


使用System;


使用System.Collections.Generic;


使用System.Text;


命名空间ConsoleApplication1


{

类课程


{


static void Main(string [] args)

{


MyObject A = new MyObject();


A.AMember = 1;


Methods.PassObjectByValue1(A);


控制台。 WriteLine(A.AMember); // 2 //即输出为''2'


MyObject B = new MyObject();


B.AMember = 1;


Methods.PassObjectByValue2(B);


Console.WriteLine(B.AMember); // 1 //也就是说,输出是''1'(不是''2'')


//而上面一行''证明''Brian'的点,''改变''下面

(workar反驳了吗?!


//////////////////////////////// //////////////////


//在这里做出改变! 解决方法


B = Methods.PassObjectByValueTWO(B); //注意使用=分配

运算符


//通过值传递更改对象?是!输出确实是

''2''不是''1''

Console.WriteLine(" B.AMember应该等于TWO!:{0 },B.AMember;


//改变结束

/////////////// //////////////////////////////////


/ *其余的这个清单显示了当你想要'b''改变''对象时''ref''优越的方式 - 这是有争议的* /


MyObject C = new MyObject();


C.AMember = 1;


Methods.PassObjectByRef1(ref C);


Console.WriteLine(C.AMember); // 2

MyObject D = new MyObject();


D.AMember = 1;


Methods.PassObjectByRef2(参考D);


Console.WriteLine(D.AMember); // 2

Console.ReadKey();


}


}
< br $>
class MyObject


{


public int AMember;


}

//////////////////// ////////////////////////////////////////////////// /////////////////////////////////////////////

//现在开始单独的源文件; //方法的开头上课使用

以上


班级方法


{


public static void PassObjectByValue1(MyObject X)


{


//我可以更改

//通过值传递的引用类型的参数


X.AMember = 2;


}


public static void PassObjectByValue2(MyObject X)


{


//我不能改变对象


//这是有争议的部分和''变通方法'的主题'

以上


X = new MyObject();


X.AMember = 2;

// Brian的观点,即AMember = 2在这里,但仍然= 1

在这里外面


}


///////// ////////////////////////////////// 是的你可以! (''workaround''

以上)

//将此函数添加到类中方法 -


public static MyObject PassObjectByValueTWO(MyObject X)

{

//你可以改变对象!


MyObject WhyNot = new MyObject() ;

WhyNot.AMember = X.AMember + 1; // 2


//现在AMember在这里2,很快就会在'2'外面


返回WhyNot; //返回MyObject类型的对象(这是

键)

}


//////// //////////////////////////////////结束是的你可以!


public static void PassObjectByRef1(ref MyObject X)


{


//我可以更改


//参考传递的参数类型参考


X.AMember = 2;


}


public static void PassObjectByRef2(ref MyObject X)


{


//我可以也改变引用的对象


X = new MyObject();


X.AMember = 2;


}


}


}

///////// ////////////////////////////////////////////////// ////////////////////////////////////////////////// ////

This post was originally in the C# Corner site, but their server is
down. I''d like to see if this group can answer.

I program in C++ and am learning C#.

The issue is: why should anybody bother in C# with pass-by-reference
using the "ref" keyword or "out" for objects in a method parameter
list, when, after all, it appears in C# that for all intents and
purposes a reference is always being passed, rather than the real
object (with, it seems, the exception of data primitives like int,
which are not ''boxed'').

The reply from C# Corner by a poster, call him Brian, as to why ''ref''
is needed was to write out a simple demonstration program (see below),
which indeed seems to refute the above, and point out that unless you
use keyword "ref" in your method parameter, then you cannot change an
object passed to a method while inside the method.

However--and this is the point of this post--it seems I''ve found a
workaround so that even with the use of "pass by value", you can
indeed change an object passed, inside the called method (when you
exit the method), if you use the assignment operator "=" and return a
new object (see below, at the comments ////). I don''t think what''s
known in C++ as ''aliasing'' is an issue here when doing this
"workaround" (correct me if I''m wrong). That''s really the point of
this post--can you have ''data aliasing'' when you pass-by-value in C#,
since we''re always dealing with references, and in theory it''s
supposed to be safe? Is there any other potential problem to my
''workaround'' below, as a coding style?

Any comments? Why do we need ''ref'' after all?

Fran

// start of console C# program

using System;

using System.Collections.Generic;

using System.Text;

namespace ConsoleApplication1

{
class Program

{

static void Main(string[] args)

{

MyObject A = new MyObject();

A.AMember = 1;

Methods.PassObjectByValue1(A);

Console.WriteLine(A.AMember);// 2 // That is, output is ''2''

MyObject B = new MyObject();

B.AMember = 1;

Methods.PassObjectByValue2(B);

Console.WriteLine(B.AMember);// 1 //That is, output is ''1'' (not ''2'')

// while the above line ''proves'' Brian''s point, the ''change'' below
(workaround) rebuts it?!

//////////////////////////////////////////////////

//change made here! "workaround"

B = Methods.PassObjectByValueTWO(B); //note use of "=" assignment
operator

//change object via pass by value? Yes! output is indeed
''2'' not ''1''

Console.WriteLine("B.AMember should equal TWO!: {0}",B.AMember);

// end of change made
/////////////////////////////////////////////////

/* rest of this listing shows how ''ref'' superior when you want to
''change'' the object--this is disputed above */

MyObject C = new MyObject();

C.AMember = 1;

Methods.PassObjectByRef1(ref C);

Console.WriteLine(C.AMember);// 2

MyObject D = new MyObject();

D.AMember = 1;

Methods.PassObjectByRef2(ref D);

Console.WriteLine(D.AMember);// 2

Console.ReadKey();

}

}

class MyObject

{

public int AMember;

}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// start of seperate source file now; // start of "Methods" class used
above

class Methods

{

public static void PassObjectByValue1(MyObject X)

{

// I can change the values of member of an

// parameter of a reference type passed by value

X.AMember = 2;

}

public static void PassObjectByValue2(MyObject X)

{

//I can''t change the object

// THIS IS THE PART ''disputed'' AND THE SUBJECT OF THE ''workaround''
above

X = new MyObject();

X.AMember = 2;
// the point by Brian being, that AMember = 2 here but still = 1
outside here

}

/////////////////////////////////////////// YES YOU CAN! (''workaround''
to above)
// add this function to the class Methods--

public static MyObject PassObjectByValueTWO (MyObject X)
{
//you can change the object!

MyObject WhyNot = new MyObject();
WhyNot.AMember = X.AMember + 1; //2

//now AMember is 2 here, and soon to be ''2'' outside too

return WhyNot; //returns object of type MyObject (this is the
key)
}

////////////////////////////////////////// END OF YES YOU CAN!

public static void PassObjectByRef1(ref MyObject X)

{

// I can change the values of member of an

// parameter of a reference type passed by ref

X.AMember = 2;

}

public static void PassObjectByRef2(ref MyObject X)

{

//I can also change the object that is referenced

X = new MyObject();

X.AMember = 2;

}

}

}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

推荐答案

Francois Appert< fr ************ @ yahoo.comwrote :
Francois Appert <fr************@yahoo.comwrote:

这篇文章最初是在C#Corner网站上,但他们的服务器是
down。我想看看这个小组是否可以回答。


我用C ++编程并且正在学习C#。


问题是:为什么有人会在C#中使用ref引用传递引用

关键字或外出对于方法参数中的对象

list,毕竟它出现在C#中,对于所有意图和

目的,总是传递引用,而不是真实的

对象(似乎是,例如int,

等数据原语的例外,它们不是''盒装'')。
This post was originally in the C# Corner site, but their server is
down. I''d like to see if this group can answer.

I program in C++ and am learning C#.

The issue is: why should anybody bother in C# with pass-by-reference
using the "ref" keyword or "out" for objects in a method parameter
list, when, after all, it appears in C# that for all intents and
purposes a reference is always being passed, rather than the real
object (with, it seems, the exception of data primitives like int,
which are not ''boxed'').



因为按值传递引用与通过引用传递

参数不同。

请参阅 http://pobox.com/~skeet/ csharp / parameters.html


-

Jon Skeet - < sk *** @ pobox.com>
< a rel =nofollowhref =http://www.pobox.com/~skeettarget =_ blank> http://www.pobox.com/~skeet 博客: http://www.msmvps.com/jon.skeet

如果回复该组,请不要给我发邮件

Because passing a reference by value isn''t the same as passing a
parameter by reference.

See http://pobox.com/~skeet/csharp/parameters.html

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too


Francois Appert写道:
Francois Appert wrote:

[。 ..]

但是,我认为,使用new(),你实际上可以做任何关键字ref能够做的事情,使用pass-ref-by-价值,而不是

如果你使用关键字''ref''和pass-ref-by-reference在它背后加了一点

。同意?
[...]
However, I think that, using new(), you can actually do anything that
keyword ref is able to do, using passing-ref-by-value, rather than
using keyword ''ref'' and passing-ref-by-reference, if you put a little
thought behind it. Agreed?



我不同意。你如何实现int.TryParse()而不通过引用传递




确实许多使用了ref。或外出是不必要的。然而,确实不会导致ref的结论。和外出他们自己

是不必要的。

I don''t agree. How would you implement int.TryParse() without passing
by reference?

It is true that many uses of "ref" or "out" are unnecessary. That does
not, however, lead to the conclusion that "ref" and "out" are themselves
unnecessary.


[...]
[...]

> ;将引用类型传递给方法时,您始终可以修改引用所指向的内容。 ref / out(或缺少它)是参考本身的参考(没有
双关语),而不是它指向的内容。
> When you pass a reference type to a method, you can always modify what
the reference points to. The ref/out (or lack of it) is in reference (no
pun intended) to the reference itself, not what it points to.



是的。但这通常很少见,因此不需要通过参考 -

参考。 (通常),只是按值传递参考,因为

参考指向的内容比

参考更重要(通常)本身。这就是为什么C#代码似乎总是省略''ref''

关键字 - 通常它并不重要。


Yes. But this is usually rare, hence no need to "pass-a-reference-by-
reference" (usually), just "pass-a-reference-by-value", since what the
reference points to is much more important (usually) than the
reference itself. That''s why C# code seems to always omit the ''ref''
keyword--usually it''s not important.



这是真的。通常你不需要通过引用传递,所以'

为什么通常不通过引用传递。但这并不意味着你不需要通过参考传递
。它只是意味着它是必要或可取的偶然的场合。


Pete

That''s true. Usually you don''t need to pass by reference, and so that''s
why usually passing by reference isn''t done. But that doesn''t mean you
don''t need passing by reference at all. It just means that the
occasions in which it''s necessary or desirable are infrequent.

Pete

8月1日上午9:51,Jon Skeet [C#MVP]< sk ... @ pobox.comwrote:
On Aug 1, 9:51 am, Jon Skeet [C# MVP] <sk...@pobox.comwrote:

因为传递参考by value与通过引用传递

参数不同。


Seehttp://pobox.com/~skeet/csharp/parameters。 html
Because passing a reference by value isn''t the same as passing a
parameter by reference.

Seehttp://pobox.com/~skeet/csharp/parameters.html



谢谢。我喜欢这个解释,虽然它需要一段时间才能获得它,但是
沉入:C#中有四种不同的参数:值

参数(默认值) ,参考参数(使用ref

修饰符),输出参数(使用out修饰符)和

参数数组(使用params修饰符)。你可以使用价值和参考类型的任何

。当你听到

" reference"或价值使用(或自己使用)你应该非常清楚自己的想法,无论你的意思是参数是一个参数是值b / b
参考或值参数,还是你的意思是涉及的类型

是参考或值类型。如果你能把这两个想法分开,那么它们很简单


Fran


Thanks. I liked this explanation, albeit it took a while for it to
sink in: "There are four different kinds of parameters in C#: value
parameters (the default), reference parameters (which use the ref
modifier), output parameters (which use the out modifier), and
parameter arrays (which use the params modifier). You can use any of
them with both value and reference types. When you hear the words
"reference" or "value" used (or use them yourself) you should be very
clear in your own mind whether you mean that a parameter is a
reference or value parameter, or whether you mean that the type
involved is a reference or value type. If you can keep the two ideas
separated, they''re very simple"

Fran


这篇关于通过引用传递vs通过值传递('数据别名'是C#中的问题?)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆