C# 在C中通过引用或值传递对象#

C# 在C中通过引用或值传递对象#,c#,parameter-passing,pass-by-reference,pass-by-value,C#,Parameter Passing,Pass By Reference,Pass By Value,在C#中,我一直认为非原语变量通过引用传递,原语值通过值传递 因此,当向方法传递任何非原语对象时,对方法中的对象所做的任何操作都会影响所传递的对象。(C#101类) 但是,我注意到,当我经过System.Drawing.Image对象时,情况似乎并非如此?如果我将system.drawing.image对象传递给另一个方法,并将图像加载到该对象上,然后让该方法超出范围并返回调用方法,则该图像不会加载到原始对象上 为什么会这样?您是如何将对象传递给方法的 您是否在该对象的方法中执行新操作?如果是这

在C#中,我一直认为非原语变量通过引用传递,原语值通过值传递

因此,当向方法传递任何非原语对象时,对方法中的对象所做的任何操作都会影响所传递的对象。(C#101类)

但是,我注意到,当我经过System.Drawing.Image对象时,情况似乎并非如此?如果我将system.drawing.image对象传递给另一个方法,并将图像加载到该对象上,然后让该方法超出范围并返回调用方法,则该图像不会加载到原始对象上


为什么会这样?

您是如何将对象传递给方法的

您是否在该对象的方法中执行新操作?如果是这样,您必须在方法中使用
ref

下面的链接给你更好的想法


您是如何将对象传递给方法的

您是否在该对象的方法中执行新操作?如果是这样,您必须在方法中使用
ref

下面的链接给你更好的想法

对象根本不会被传递。默认情况下,将对参数求值,并按值传递其值,作为所调用方法的参数的初始值。现在重要的一点是,该值是引用类型的引用—一种获取对象(或null)的方法。调用方可以看到对该对象的更改。但是,当您使用“传递值”(所有类型的默认值)时,将参数的值更改为引用其他对象将不可见

如果要使用按引用传递,无论参数类型是值类型还是引用类型,都必须使用
out
ref
。在这种情况下,实际上变量本身是通过引用传递的,因此参数使用与参数相同的存储位置,并且调用者可以看到对参数本身的更改

因此:

我有一本书。基本上,“通过引用传递”并不意味着你认为它的意思。

对象根本不被传递。默认情况下,将对参数求值,并按值传递其值,作为所调用方法的参数的初始值。现在重要的一点是,该值是引用类型的引用—一种获取对象(或null)的方法。调用方可以看到对该对象的更改。但是,当您使用“传递值”(所有类型的默认值)时,将参数的值更改为引用其他对象将不可见

如果要使用按引用传递,无论参数类型是值类型还是引用类型,都必须使用
out
ref
。在这种情况下,实际上变量本身是通过引用传递的,因此参数使用与参数相同的存储位置,并且调用者可以看到对参数本身的更改

因此:


我有一本书。基本上,“按引用传递”并不是您认为它的意思。

当您将
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
}

当您将
System.Drawing.Image
type对象传递给某个方法时,实际上是在向该对象传递引用的副本

因此,如果在该方法中加载新图像,则使用“新建/复制”引用加载。您没有对原始文件进行更改

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

TestRef:5

TestObjPlain:test

TestObjRef:TestObjRef


另一个代码示例演示了这一点:

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

TestRef:5

TestObjPlain:test

TestObjRef:TestObjRef


在“按引用传递”中,您仅在函数参数中添加“ref”和一个 更重要的是,您应该声明函数“static”,因为main是静态的(#
public void main(String[]args)


在“按引用传递”中,您仅在函数参数中添加“ref”和一个 更重要的是,您应该声明函数“static”,因为main是静态的(#
public void main(String[]args)


我想你这样做会更清楚。我建议下载来测试这样的东西

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";
}
这应该会输出

WontUpdate

名字:Egli,姓氏:Becerra

快速更新

名字:法维奥,姓氏:贝塞拉

明确更新


名字:法维奥,姓氏:贝塞拉我想你这样做会更清楚。我建议下载来测试这样的东西

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";
}
这应该会输出

WontUpdate

名字:Egli,姓氏:Becerra

快速更新

名字:法维奥,姓氏:贝塞拉

明确更新


名字:法维奥,姓氏:贝塞拉

添加了很多好答案。我仍然想贡献自己的力量,也许它会稍微澄清一些

当您将实例作为参数传递给方法时,它将传递实例的副本。现在,如果您传递的实例是
值类型
(位于
堆栈中
),那么您将传递该值的副本,因此如果您修改它,它将不会反映在调用方中。如果实例是引用类型,则将引用的副本(再次驻留在
堆栈中)传递给对象。所以你得到了对同一个对象的两个引用。它们都可以修改对象。但是如果在方法体中实例化新对象,那么引用的副本将不再引用原始对象,它将引用新对象