在c#中,我一直认为非基本变量是通过引用传递的,而基本值是通过值传递的。

因此,当向一个方法传递任何非基本对象时,在方法中对该对象所做的任何操作都会影响正在传递的对象。(c# 101的东西)

然而,我已经注意到,当我传递一个System.Drawing.Image对象,这似乎不是这样的情况?如果我将system。drawing。image对象传递给另一个方法,并将图像加载到该对象上,然后让该方法超出作用域并返回调用方法,图像没有加载到原始对象上?

为什么会这样?


如何将对象传递给方法?

你在那个for object方法中做了新的吗?如果是,你必须使用ref in method。

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

http://dotnetstep.blogspot.com/2008/09/passing-reference-type-byval-or-byref.html


Objects aren't passed at all. By default, the argument is evaluated and its value is passed, by value, as the initial value of the parameter of the method you're calling. Now the important point is that the value is a reference for reference types - a way of getting to an object (or null). Changes to that object will be visible from the caller. However, changing the value of the parameter to refer to a different object will not be visible when you're using pass by value, which is the default for all types.

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

So:

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(...);
}

我有一篇文章对此进行了更详细的介绍。基本上,“通过引用传递”并不是你所想的那样。


当你将System.Drawing.Image类型对象传递给一个方法时,你实际上是在传递该对象引用的副本。

如果在这个方法中你要加载一个新图像你是在使用new/ replicated reference来加载。你没有改变原来的样子。

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:test TestObjRef:TestObjRef


在Pass By Reference中,只在函数参数和一个参数中添加“ref” 更多的事情你应该声明函数“static”,因为main是静态的(#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";
}

然后输出

WontUpdate

名:Egli,姓:Becerra

更新隐式

名:法维奥,姓:贝塞拉

UpdateExplicitly

名:法维奥,姓:贝塞拉


很多好的答案被添加了进来。我还是想做点贡献,可能会更清楚一点。

When you pass an instance as an argument to the method it passes the copy of the instance. Now, if the instance you pass is a value type(resides in the stack) you pass the copy of that value, so if you modify it, it won't be reflected in the caller. If the instance is a reference type you pass the copy of the reference(again resides in the stack) to the object. So you got two references to the same object. Both of them can modify the object. But if within the method body, you instantiate new object your copy of the reference will no longer refer to the original object, it will refer to the new object you just created. So you will end up having 2 references and 2 objects.


在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";
  }
}