[C#] C #에서 참조 또는 값으로 객체 전달

C #에서 필자는 기본이 아닌 변수는 참조로 전달되고 기본 값은 값으로 전달된다고 생각했습니다.

따라서 기본이 아닌 객체를 메소드에 전달할 때 메소드의 객체에 수행 된 모든 작업은 객체가 전달되는 데 영향을 미칩니다. (C # 101 물건)

그러나 System.Drawing.Image 개체를 전달할 때 이것이 그렇지 않은 것으로 나타났습니다. system.drawing.image 객체를 다른 메소드에 전달하고 해당 객체에 이미지를로드 한 다음 해당 메소드가 범위를 벗어나 호출 메소드로 돌아 가면 해당 이미지가 원래 객체에로드되지 않습니까?

왜 이런거야?



답변

객체 는 전혀 전달되지 않습니다. 기본적으로 인수는 평가되고 해당 은 호출하는 메서드 매개 변수의 초기 값으로 값별로 전달됩니다. 이제 중요한 점은 값이 참조 유형에 대한 참조-객체에 도달하는 방법 (또는 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(...);
}

나는 이것에 훨씬 더 많은 기사를 가지고있다 . 기본적으로 “참조로 전달”이 의미하는 바를 의미하지는 않습니다.


답변

이것을 보여주는 또 하나의 코드 샘플 :

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

그리고 출력 :

TestPlain : 0

TestRef : 5

TestObjPlain : 테스트

TestObjRef : 테스트 ObjRef


답변

좋은 답변이 많이 추가되었습니다. 나는 여전히 공헌하고 싶습니다. 약간 더 명확해질 것입니다.

인스턴스를 메소드에 인수로 전달하면 인스턴스의 인스턴스를 전달합니다 copy. 이제 전달하는 인스턴스가 value type( stack)에 있으면 해당 값 의 사본 을 전달 하므로 수정하면 호출자에게 반영되지 않습니다. 인스턴스가 참조 유형 인 경우 참조 사본 ( stack)이 객체에 전달됩니다. 따라서 동일한 객체에 대한 두 개의 참조가 있습니다. 둘 다 객체를 수정할 수 있습니다. 그러나 메소드 본문 내에서 새 오브젝트를 인스턴스화하면 참조 사본이 더 이상 원래 오브젝트를 참조하지 않고 방금 작성한 새 오브젝트를 참조합니다. 따라서 2 개의 참조와 2 개의 객체가 생깁니다.


답변

당신이 이렇게하면 더 명확하다고 생각합니다. 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

암시 적으로 업데이트

이름 : 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방법 을 사용해야 합니다.

다음 링크는 더 나은 아이디어를 제공합니다.

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


답변

Pass By Reference에서 함수 매개 변수에는 “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);
        }
    }
}