提问人:Michael 提问时间:1/3/2012 最后编辑:nawfalMichael 更新时间:9/29/2021 访问量:342423
在 C 中按引用或值传递对象#
Passing Objects By Reference or Value in C#
问:
在 C# 中,我一直认为非原始变量是通过引用传递的,而原始值是通过值传递的。
因此,当将任何非基元对象传递给方法时,对方法中的对象所做的任何事情都会影响正在传递的对象。(C# 101 内容)
但是,我注意到当我传递System.Drawing.Image对象时,情况似乎并非如此?如果我将 system.drawing.image 对象传递给另一个方法,并将图像加载到该对象上,然后让该方法超出范围并返回调用方法,则该图像不会加载到原始对象上?
为什么会这样?
答:
你是如何将对象传递给方法的?
您是否在该方法中为对象做新操作?如果是这样,您必须使用 in 方法。ref
以下链接为您提供更好的主意。
http://dotnetstep.blogspot.com/2008/09/passing-reference-type-byval-or-byref.html
根本不传递对象。默认情况下,将计算参数,并按 value 传递其值,作为要调用的方法的参数的初始值。现在重要的一点是,该值是引用类型的引用 - 一种获取对象(或 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
myobj
当您将类型对象传递给某个方法时,您实际上是在向该对象传递引用的副本。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
}
评论
还有一个代码示例来展示这一点:
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
评论
在传递引用中,您只在函数参数中添加“ref”和一个
您应该声明函数“static”的更多内容,因为 main 是 static(#)!public void main(String[] args)
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);
}
}
}
我想当你这样做时会更清楚。我建议下载 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";
}
这应该输出
不会更新
名字:埃格利,姓氏:贝塞拉
UpdateImplicitly
名字:Favio,姓氏:Becerra
UpdateExplicitly
名字:Favio,姓氏:Becerra
评论
添加了很多很好的答案。我仍然想做出贡献,也许它会稍微澄清一点。
当您将实例作为参数传递给方法时,它会传递实例的参数。现在,如果您传递的实例是 (驻留在 中),则传递该值的副本,因此,如果您修改它,它不会反映在调用方中。如果实例是引用类型,则将引用的副本(再次驻留在 中)传递给对象。因此,您得到了对同一对象的两个引用。它们都可以修改对象。但是,如果在方法主体中实例化新对象,则引用的副本将不再引用原始对象,它将引用刚刚创建的新对象。因此,您最终将拥有 2 个引用和 2 个对象。copy
value type
stack
stack
评论
在最新版本的 C# 中(在撰写本文时为 C# 9),对象默认由 传递。因此,对调用函数中的对象所做的任何更改都将保留在被调用函数中的对象中。ref
评论
Employee e = new Employee();
e.Name = "Mayur";
//Passes the reference as value. Parameters passed by value(default).
e.ReferenceParameter(e);
Console.WriteLine(e.Name); // It will print "Shiv"
class Employee {
public string Name { get; set; }
public void ReferenceParameter(Employee emp) {
//Original reference value updated.
emp.Name = "Shiv";
// New reference created so emp object at calling method will not be updated for below changes.
emp = new Employee();
emp.Name = "Max";
}
}
上一个:在 C 中通过引用传递
评论
image.Load(filename)
image = Image.Load(filename)
image