在C#中,我一直认为非原始变量是通过引用传递的,原始值是通过值传递的。
因此,当将任何非原始对象传递给方法时,对该方法中的对象执行的任何操作都会影响要传递的对象。(C#101的东西)
但是,我注意到当我传递System.Drawing.Image对象时,似乎不是这样吗?如果我将system.drawing.image对象传递给另一个方法,然后将图像加载到该对象上,然后让该方法超出范围并返回到调用方法,则该图像未加载到原始对象上吗?
为什么是这样?
在C#中,我一直认为非原始变量是通过引用传递的,原始值是通过值传递的。
因此,当将任何非原始对象传递给方法时,对该方法中的对象执行的任何操作都会影响要传递的对象。(C#101的东西)
但是,我注意到当我传递System.Drawing.Image对象时,似乎不是这样吗?如果我将system.drawing.image对象传递给另一个方法,然后将图像加载到该对象上,然后让该方法超出范围并返回到调用方法,则该图像未加载到原始对象上吗?
为什么是这样?
Answers:
根本不传递对象。默认情况下,对参数进行求值,并按值将其值作为您所调用方法的参数的初始值传递。现在重要的一点是,该值是对引用类型的引用-一种访问对象(或为null)的方法。对该对象的更改将在呼叫者处可见。但是,当您使用按值传递时,更改参数的值以引用其他对象将不可见,这是所有类型的默认值。
如果要使用按引用传递,则无论参数类型是值类型还是引用类型,都必须使用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(...);
}
我有一篇文章对此进行了更详细的介绍。基本上,“通过引用”并不意味着您认为它意味着什么。
ref
并out
从c#中删除,可以肯定地说c#传递参数的方式与java相同,即始终按值传递。与Java有什么区别。
另一个代码示例展示了这一点:
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 TestPlain(int i)
{
i = 5;
}
public static void TestRef(ref int i)
{
i = 5;
}
public static void TestObjPlain(string s)
{
s = "TestObjPlain";
}
public static void TestObjRef(ref string s)
{
s = "TestObjRef";
}
并输出:
测试平原:0
测试编号:5
TestObjPlain:测试
TestObjRef:TestObjRef
我想当您这样做时,它会更加清晰。我建议下载LinqPad来测试类似的事情。
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";
}
那应该输出
更新
名:Egli,姓:Becerra
隐式更新
名:Favio,姓:Becerra
明确更新
名: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
}
您如何将对象传递给方法?
您是否正在使用该对象的新方法?如果是这样,则必须使用ref
in方法。
以下链接为您提供了更好的主意。
http://dotnetstep.blogspot.com/2008/09/passing-reference-type-byval-or-byref.html
在“按引用传递”中,您只需在函数参数中添加“ ref”,由于main是static(#public void main(String[] args)
),您应该声明函数“ static” !
namespace preparation
{
public class Program
{
public static void swap(ref int lhs,ref int rhs)
{
int temp = lhs;
lhs = rhs;
rhs = temp;
}
static void Main(string[] args)
{
int a = 10;
int b = 80;
Console.WriteLine("a is before sort " + a);
Console.WriteLine("b is before sort " + b);
swap(ref a, ref b);
Console.WriteLine("");
Console.WriteLine("a is after sort " + a);
Console.WriteLine("b is after sort " + b);
}
}
}