mic*_*ael 217 c# parameter-passing pass-by-reference pass-by-value
在C#中,我一直认为非原始变量是通过引用传递的,而原始值是通过值传递的.
因此,当将任何非基本对象传递给方法时,对方法中的对象所做的任何操作都会影响传递的对象.(C#101的东西)
但是,我注意到当我传递一个System.Drawing.Image对象时,情况似乎并非如此?如果我将system.drawing.image对象传递给另一个方法,并将图像加载到该对象上,那么让该方法超出范围并返回调用方法,该图像未加载到原始对象上?
为什么是这样?
Jon*_*eet 459
根本没有传递对象.默认情况下,将对参数进行求值,并将其值按值传递为您正在调用的方法的参数的初始值.现在重要的一点是该值是引用类型的引用 - 一种获取对象(或null)的方法.调用者可以看到对该对象的更改.但是,当您使用传递值时,更改参数的值以引用其他对象将不可见,这是所有类型的默认值.
如果要使用pass-by-reference,则必须使用out或ref,参数类型是值类型还是引用类型.在这种情况下,实际上变量本身是通过引用传递的,因此参数使用与参数相同的存储位置 - 并且调用者可以看到对参数本身的更改.
所以:
public void Foo(Image image)
{
// This change won't be seen by the caller: it's changing the value
// of the parameter.
image = Image.FromStream(...);
}
public void Foo(ref Image image)
{
// This change *will* be seen by the caller: it's changing the value
// of the parameter, but we're using pass by reference
image = Image.FromStream(...);
}
public void Foo(Image image)
{
// This change *will* be seen by the caller: it's changing the data
// within the object that the parameter value refers to.
image.RotateFlip(...);
}
Run Code Online (Sandbox Code Playgroud)
我有一篇文章详细介绍了这一点.基本上,"通过引用传递"并不意味着您认为它意味着什么.
Ole*_*egI 51
添加了很多好的答案。我仍然想做出贡献,也许它会稍微澄清一点。
当您将实例作为参数传递给方法时,它会传递copy实例的 。现在,如果您传递的实例是 a value type(驻留在 中stack),您将传递该值的副本,因此如果您修改它,它将不会反映在调用方中。如果实例是引用类型,则将引用的副本(再次驻留在 中stack)传递给对象。所以你有两个对同一个对象的引用。他们都可以修改对象。但是,如果在方法体中实例化新对象,您的引用副本将不再引用原始对象,它将引用您刚刚创建的新对象。所以你最终会有 2 个引用和 2 个对象。
vmg*_*vmg 18
还有一个代码示例来展示这个:
void Main()
{
int k = 0;
TestPlain(k);
Console.WriteLine("TestPlain:" + k);
TestRef(ref k);
Console.WriteLine("TestRef:" + k);
string t = "test";
TestObjPlain(t);
Console.WriteLine("TestObjPlain:" +t);
TestObjRef(ref t);
Console.WriteLine("TestObjRef:" + t);
}
public static void TestRef(ref int i)
{
i = 5;
}
public static void TestPlain(int i)
{
i = 5;
}
public static void TestObjRef(ref string s)
{
s = "TestObjRef";
}
public static void TestObjPlain(string s)
{
s = "TestObjPlain";
}
Run Code Online (Sandbox Code Playgroud)
并输出:
TestPlain:0
TestRef:5
TestObjPlain:测试
TestObjRef:TestObjRef
当你这样做的时候我觉得它更清楚了.我建议下载LinkPad来测试这样的东西.
void Main()
{
var Person = new Person(){FirstName = "Egli", LastName = "Becerra"};
//Will update egli
WontUpdate(Person);
Console.WriteLine("WontUpdate");
Console.WriteLine($"First name: {Person.FirstName}, Last name: {Person.LastName}\n");
UpdateImplicitly(Person);
Console.WriteLine("UpdateImplicitly");
Console.WriteLine($"First name: {Person.FirstName}, Last name: {Person.LastName}\n");
UpdateExplicitly(ref Person);
Console.WriteLine("UpdateExplicitly");
Console.WriteLine($"First name: {Person.FirstName}, Last name: {Person.LastName}\n");
}
//Class to test
public class Person{
public string FirstName {get; set;}
public string LastName {get; set;}
public string printName(){
return $"First name: {FirstName} Last name:{LastName}";
}
}
public static void WontUpdate(Person p)
{
//New instance does jack...
var newP = new Person(){FirstName = p.FirstName, LastName = p.LastName};
newP.FirstName = "Favio";
newP.LastName = "Becerra";
}
public static void UpdateImplicitly(Person p)
{
//Passing by reference implicitly
p.FirstName = "Favio";
p.LastName = "Becerra";
}
public static void UpdateExplicitly(ref Person p)
{
//Again passing by reference explicitly (reduntant)
p.FirstName = "Favio";
p.LastName = "Becerra";
}
Run Code Online (Sandbox Code Playgroud)
这应该输出
WontUpdate
名:Egli,姓:Becerra
UpdateImplicitly
名:Favio,姓:Becerra
UpdateExplicitly
名:Favio,姓:Becerra
当您将System.Drawing.Image类型对象传递给方法时,您实际上是在传递对该对象的引用副本。
因此,如果在该方法中您正在加载使用新/复制引用加载的新图像。你不是在改变原作。
YourMethod(System.Drawing.Image image)
{
//now this image is a new reference
//if you load a new image
image = new Image()..
//you are not changing the original reference you are just changing the copy of original reference
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
190796 次 |
| 最近记录: |