2014-09-26 1 views
2

직장에서 우리는 방법을 통해 사본을 보낸 후 원본 개체가 변경된 문제가 발생했습니다. 원래 클래스에서 IClonable을 사용하여 해결 방법을 찾았지만 왜 처음 발생했는지 알 수 없었습니다.ref 인수를 사용하지 않고 복사 한 후 원본 객체가 변경된 이유는 무엇입니까?

우리는이 예제 코드를 작성하여 문제를 재현하고 (원래 코드와 유사 함) 누군가가 왜 그런지 설명 할 수 있기를 바랍니다. 당신이 볼 수 있듯이

public partial class ClassRefTest : System.Web.UI.Page 
{ 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     var myclass = new MyClass(); 
     var copy = myclass; 
     myclass.Mystring = "jadajadajada"; 
     Dal.DoSomeThing(copy); 

     lit.Text = myclass.Mystring; //Text is expected to be jadajadajada, 
             but ends up to be referenced 
    } 
} 

public class MyClass 
{ 
    public string Mystring { get; set; } 
} 

public static class Dal 
{ 
    public static int? DoSomeThing(MyClass daclass) 
    { 
     daclass.Mystring = "referenced"; 
     return null; 
    } 

} 

DoSomething() 방법에서 우리는 어떤 ref 인수를 사용하지 만, 여전히 lit.Text는 참조 할 수 끝납니다.

왜 이런 일이 발생합니까? 당신의 MyClass 그것이 여기에 예상되는 동작 왜 당신은 원본 데이터에 대한 참조를하지 데이터 자체이 전달되도록 참조 형식이기 때문에 정상

+4

Jon Skeet [Parameters passing in C#] (http://www.yoda.arachsys.com/csharp/parameters.html) – Habib

+0

참고 자료 [String.Copy] (http : // msdn.microsoft.com/en-us/library/system.string.copy(v=vs.110).aspx) 문자열을 복사하지만 참조 링크가 분리되어 분리됩니다. – alykins

+0

[Joesph Albahari가 읽어야]] (http://www.albahari.com/valuevsreftypes.aspx) –

답변

7

""입니다. 물론 나의 설명은 Jon Skeet one 또는 Joseph Albahari의 웅장 함과 같을 수는 없지만 나는 시도 할 것이다.

C 프로그래밍의 옛날에는 포인터 개념을 이해하는 것이 그 언어로 작업하는 근본이었습니다. 수년이 지났지 만 지금은 참고 문헌이라고 부르지 만 여전히 영광스런 포인터입니다. 어떻게 작동하는지 이해하면 프로그래머가되는 것의 절반이됩니다 (농담)

참조 정보 ? 매우 짧은 대답으로 나는 말할 것이다. 변수에 저장된 숫자이며이 숫자는 데이터가있는 메모리의 주소를 나타냅니다.
참조가 필요한 이유는 무엇입니까? 왜냐하면 모든 필드가 코드와 함께 움직이는 전체 객체를 갖는 대신 데이터의 메모리 영역을 읽을 수있는 단일 숫자를 처리하는 것이 매우 간단하기 때문입니다.

그럼, 우리가 우리 모두는이 클래스 MyClass의 생성자를 호출하는 것을 알고

var myclass = new MyClass(); 

쓰기,하지만 프레임 워크는 또한 메모리 영역을 제공하는 요청입니다 때 발생하는 곳 인스턴스의 값 (속성, 필드 및 기타 내부 하우스 키핑 정보)은 특정 시점에 존재하고 존재합니다. MyClass가 필요한 모든 것을 저장하기 위해 100 바이트를 필요로한다고 가정하십시오. 프레임 워크는 어떤 식 으로든 컴퓨터 메모리를 검색하고 주소 4200으로 식별되는 메모리에서 장소를 찾는다 고 가정합시다.이 값 (4200)은 var myclass에 할당 된 값입니다. 메모리에 대한 포인터입니다 (oops it 객체 인스턴스에 대한 참조입니다.

전화 할 때 어떻게됩니까?

var copy = myclass; 

특별한 것은 없습니다. copy 변수의 값은 myclass (4200)이됩니다. 그러나 두 변수는 동일한 메모리 영역을 참조하므로 어느 하나를 사용하면 아무런 차이가 없습니다. 메모리 영역 (MyClass의 인스턴스)이 아직이 속성에 의해 점유 된 메모리 영역을 찾는 기준 값과 상기 기준 값을 사용하여 그 값을 설정한다 (4200)

myclass.Mystring = "jadajadajada"; 

가상의 메모리 어드레스에 위치하고 리터럴 문자열이 유지되는 영역 intern. 포인터를 사용하여 비유 할 수 있다면 기본 메모리 (4200)를 가져 와서 오프셋을 추가하여 적절한 MyString을 나타내는 참조가 객체 인스턴스가 차지하는 100 바이트의 경계 내에 유지되는 지점을 찾으십시오. MyString 참조가 메모리 영역의 시작 부분에서 42 바이트 뒤에 있다고 가정 해 봅시다. 42에서 4200 yelds 4242를 추가하면 문자 "jadajadajada"에 대한 참조가 저장됩니다.

여기 (문제가있는 요점). copy 변수를 전달할 때 프레임 워크가 메모리 영역 검색을 반복하고 새 영역의 원래 영역의 모든 내용을 복사한다고 생각하지 마십시오. 아니요, 실제로는 불가능합니다 (MyClass에 다른 클래스의 인스턴스 인 속성이 포함되어 있다고 생각하면 멈출 수 없습니다.) DoSomeThing 메서드에 전달 된 값은 다시 참조 값 4200입니다. 명시 적으로 var copy = myclass;로 이전했을처럼 값이 자동 DoSomething에 대한 입력 매개 변수로 선언 된 지역 변수 daclass에 할당 (그것은이다.이 시점에서

는 같은 메모리 영역에 daClass 행위를 사용하는 모든 작업이 점유 것이 분명하다 원래 인스턴스에서 코드가 시작 지점으로 되돌아 왔을 때 결과를 볼 수 있습니다.

더 전문적인 사용자로부터 용서를 구합니다. 이리. 특히 캐주얼하고 부정확 한 용어로 '메모리 주소'를 사용하는 경우.

+0

아, 왜 그런지 설명합니다. 감사합니다. 감사합니다. 정보를 위해! – AssaultingCuccos

4

참조 형식이 Parameter passing in C#

에서 무엇인지에 대한 설명입니다

참조 유형은 데이터 자체가 아니라 적절한 데이터에 대한 참조를 값으로 갖는 유형입니다.

+3

* string은 참조 객체입니다 *는 여기에 관계 없습니다. –

+0

@SriramSakthivel 그렇습니다. 참조 유형에 포함 된 값이 int와 같은 값 유형이라 할지라도 참조 유형에 캡슐화되었으므로 관련이 없습니다. 그러나 OP와 동일한 값을 얻습니다. –

1

MSDN의 문서는 매우 명확하게 말합니다. 값 유형은 기본적으로 사본으로 전달되며 객체는 기본적으로 참조로 전달됩니다. 내가 여기에 두 가지 문제를 참조 Methods in C#

0

...

객체

VAR 복사 = myClass가의 사본을 만들기; 복사본을 만들지 않습니다. 실제로 "myClass"라는 두 번째 참조 ("포인터")를 만듭니다 (변수 "copy"의 이름을 잘못 지정하는 것입니다). 따라서 여러분은 myClass와 copy가 동일한 정확한 객체를 가리키고 있습니다. 나는 새로운 객체를 생성

var copy = new MyClass(myClass); 

주의 사항 :

당신이 뭔가를해야 할 사본을 확인하십시오. REF없이 치형 변수를 전달할 때 참조
  1. 지나가는

    는 변수는 수신 방식에 의해 변경 될 수 없다.

    예제 DoSomething (int foo) - DoSomething은 외부의 foo 값에 영향을 줄 수 없습니다. REF와 치형 변수를 전달할 때

  2. 는 변수

    을 변경할 수 예제 해봐요 (심판 INT foo에) - 해봐요 푸 변경되면, 그 변경 상태를 유지한다.

  3. ref를 사용하지 않고 개체를 전달하면 개체의 데이터를 변경할 수 있지만 개체에 대한 참조는 변경할 수 없습니다.

    무효 DoSomething (MyClass myClass) { myClass.myString = "ABC"// 문자열이 ABC로 설정됩니다. myClass = new MyClass(); // 영향이 없거나 허용되지 않을 수도 있음 }

  4. ref를 사용하여 객체를 전달할 때 객체의 데이터를 변경하고 객체에 대한 참조를 변경할 수 있습니다.

    무효 해봐요 (REF MyClass에 myClass가) 가 { myClass.myString가 = "ABC"// 문자열이) (ABC에 = myClass가 새로운 MyClass에 설정되고; myClass가이 을 변경 한 이후 // 문자열은 지금이 작동 방법을 설명하는 것이 재미있다}

관련 문제