C\#깊이 복사 에 대한 심도 있 는 해석
앞에서 우 리 는 디자인 모델 을 배 웠 는데 그 중에서 우 리 는 원형 모델 을 알 게 되 었 다.여기 에는 복제 자체 의 대상 이 언급 되 어 있다.그럼 대상 을 복사 하 는 거 야?여기에 이런 개념 이 언급 되 었 다.깊 고 얕 은 복사,깊 은 복사 가 무엇 입 니까?얕 은 복사 가 무엇 입 니까?같이 보 자.
얕 은 복사
우선 얕 은 복사 본 을 봅 시다.얕 은 복사 본 은 대상 의 모든 필드 를 새로운 대상 에 복사 하 는 것 으로 얕 은 복사 본 은 값 유형 과 인용 유형 에 서로 다른 영향 을 미친다.값 형식의 값 이 던 전 으로 복사 되면 던 전의 값 을 수정 하면 원래 대상 의 값 에 영향 을 주지 않 습 니 다.그러나 인용 형식 이 복사 본 에 복 사 된 것 은 인용 형식의 인용 입 니 다.인용 대상 이 아니다.이렇게 복사 본 중의 값 을 수정 하면 원래 대상 의 값 도 수정 된다.그러나 이 인용 형식 은 문자열 String 형식 을 제외 해 야 합 니 다.
그렇다면 왜 인용 형식 수정 사본 의 값 은 원래 대상 의 값 변 화 를 일 으 키 고 string 문자열 형식 은 제 외 됩 니까?우선 이러한 개념 을 알 아야 합 니 다.string 형식 은 가 변 적 이지 않 은 데이터 형식 입 니 다.즉,문자열 대상 을 초기 화 했다 는 것 을 의미 합 니 다.이 문자열 대상 은 바 꿀 수 없습니다.겉으로 문자열 의 내용 을 수정 하 는 방법 과 연산 은 실제로 새로운 문자열 을 만 든 다음 필요 에 따라 오래된 문자열 의 내용 을 새 문자열 로 복사 할 수 있 습 니 다.어떻게 이해 해?우 리 는 아래 의 이 사례 를 본다.
#region
/// <summary>
///
/// </summary>
/// <param name="o"></param>
/// <returns></returns>
public static string getMemory(object o)
{
GCHandle h = GCHandle.Alloc(o, GCHandleType.Pinned);
IntPtr addr = h.AddrOfPinnedObject();
return "0x" + addr.ToString("X");
}
/// <summary>
///
/// </summary>
public static void Compares()
{
string a = "123";
Console.WriteLine("a :\t\t" + getMemory(a));
string b = "123";
Console.WriteLine("b :\t\t" + getMemory(b));
Console.WriteLine("a b :\t\t" + Object.ReferenceEquals(a, b));
b = "456";
Console.WriteLine("b :\t\t" + getMemory(b));
}
#endregion
여기 서 우 리 는 a="123",b="123"을 본다.우 리 는 그들의 인용 주 소 를 보 았 다.즉,우리 가 먼저 a 를 만 들 때 문자열 a 를 만 들 었 고 인용 주소 가 생 겼 다 는 것 이다.그리고 b 를 만 들 때 같은 값 이 있 는 지 먼저 찾 습 니 다.같은 값 이 존재 하면 인용 주 소 를 가 져 옵 니 다.이것 이 바로 a 와 b 의 인용 주소 가 같은 이유 이다.여기 에는 문자 주둔지 라 는 것 이 관련 되 어 있다.문자열 을 저장 합 니 다.그러면 다음 에 우 리 는 b 의 값 을 수정 하고 인용 주 소 를 출력 합 니 다.이전의 인용 주소 와 다르다 는 것 을 알 게 되 었 습 니 다.설명 은 원래 값 을 수정 하 는 것 이 아니 라 문자열 을 다시 만 들 고 인용 주 소 를 다시 가 져 왔 습 니 다.
다음은 얕 은 복사 사례 를 살 펴 보 겠 습 니 다.먼저 다음 과 같은 데이터 형식의 값 을 준비 합 니 다.int,string,enum,struct,class,int[],string[].
/// <summary>
///
/// </summary>
public enum EnumTest
{
TestOne = 1,
TestTwo = 2
}
/// <summary>
///
/// </summary>
public struct StructTest
{
public int Test;
public StructTest(int i)
{
Test = i;
}
}
/// <summary>
///
/// </summary>
public class ClassTest
{
public string TestString;
public ClassTest(string _string)
{
TestString = _string;
}
}
/// <summary>
///
/// </summary>
public class DeepClone : ICloneable
{
public int _int = 1;
public string _string = "1";
public EnumTest _enum = EnumTest.TestOne;
public StructTest _struct = new StructTest(1);
public ClassTest _class = new ClassTest("1");
public int[] arrInt = new int[] { 1 };
public string[] arrString = new string[] { "1" };
public object Clone()
{
var NewOne = JsonConvert.SerializeObject(this);
return JsonConvert.DeserializeObject<DeepClone>(NewOne);
}
}
class Program
{
static void Main(string[] args)
{
DeepClone simple = new DeepClone();
var simpleTwo = (DeepClone)simple.Clone();
simpleTwo._int = 2;
simpleTwo._string = "2";
simpleTwo._enum = EnumTest.TestTwo;
simpleTwo._struct.Test = 2;
simpleTwo._class.TestString = "2";
simpleTwo.arrInt[0] = 2;
simpleTwo.arrString[0] = "2";
Console.WriteLine($"int :{simple._int}\t\t :{simpleTwo._int}");
Console.WriteLine($"string :{simple._string}\t\t :{simpleTwo._string}");
Console.WriteLine($"enum :{(int)simple._enum}\t\t :{(int)simpleTwo._enum}");
Console.WriteLine($"struct :{simple._struct.Test}\t\t :{simpleTwo._struct.Test}");
Console.WriteLine($"class :{simple._class.TestString}\t\t :{simpleTwo._class.TestString}");
Console.WriteLine($"int :{simple.arrInt[0]}\t\t :{simpleTwo.arrInt[0]}");
Console.WriteLine($"string :{simple.arrString[0]}\t\t :{simpleTwo.arrString[0]}");
}
}
우 리 는 ICloneable 인 터 페 이 스 를 계승 하여 이 유형 들 을 모두 얕 게 복사 한 후에 복사 본 대상 을 수정 했다.출력 대상 과 던 전 대상 을 비교 합 니 다.int,enum,struct,값 유형 및 string 이라는 특수 한 인용 유형의 원래 대상 값 이 변 하지 않 았 음 을 발 견 했 습 니 다.그러나 class,int[],string[]이 인용 유형 대상 의 원래 대상 이 영향 을 받 아 값 이 바 뀌 었 습 니 다.우리 가 앞에서 말 한 것 을 다시 한 번 검증 했다.얕 은 복사 본 은 대상 을 복사 본 대상 에 할당 하고 값 형식 복사 값 을 참조 형식 으로 참조 대상 을 복사 하 는 것 입 니 다.복사 본 대상 값 을 수정 합 니 다.값 형식 과 string 원래 대상 은 영향 을 받 지 않 습 니 다.인용 유형 은 string 을 제외 하고 원래 대상 은 모두 영향 을 받 습 니 다.
딥 카피
우리 위 에서 얕 은 복사 본 을 보 았 는데,얕 은 복사 본 은 여전히 일정한 영향 을 미 치 므 로,잘 처리 하지 못 하면 bug 가 될 수 있다.그럼 그 에 대응 하 는 딥 카피 가 어떤 건 지 볼 까요?여기 서 먼저 설명 할 수 있 습 니 다.깊이 복사 하 는 것 은 값 유형 과 인용 유형 에 대해 다 르 지 않 습 니 다.딥 복사 도 대상 의 모든 필드 를 새 대상 에 복사 하지만 대상 은 값 형식 이 든 인용 형식 이 든 다시 만 들 고 복사 본 대상 으로 복사 합 니 다.던 전 대상 에 대한 수정 은 어떠한 유형 에 도 영향 을 주지 않 습 니 다.
우 리 는 위의 예 를 계속 깊이 복사 해 보 자.
/// <summary>
///
/// </summary>
public class DeepClone : ICloneable
{
public int _int = 1;
public string _string = "1";
public EnumTest _enum = EnumTest.TestOne;
public StructTest _struct = new StructTest(1);
public ClassTest _class = new ClassTest("1");
public int[] arrInt = new int[] { 1 };
public string[] arrString = new string[] { "1" };
public object Clone()
{
var NewOne = JsonConvert.SerializeObject(this);
return JsonConvert.DeserializeObject<DeepClone>(NewOne);
}
}
class Program
{
static void Main(string[] args)
{
DeepClone simple = new DeepClone();
var simpleTwo = (DeepClone)simple.Clone();
simpleTwo._int = 2;
simpleTwo._string = "2";
simpleTwo._enum = EnumTest.TestTwo;
simpleTwo._struct.Test = 2;
simpleTwo._class.TestString = "2";
simpleTwo.arrInt[0] = 2;
simpleTwo.arrString[0] = "2";
Console.WriteLine($"int :{simple._int}\t\t :{simpleTwo._int}");
Console.WriteLine($"string :{simple._string}\t\t :{simpleTwo._string}");
Console.WriteLine($"enum :{(int)simple._enum}\t\t :{(int)simpleTwo._enum}");
Console.WriteLine($"struct :{simple._struct.Test}\t\t :{simpleTwo._struct.Test}");
Console.WriteLine($"class :{simple._class.TestString}\t\t :{simpleTwo._class.TestString}");
Console.WriteLine($"int :{simple.arrInt[0]}\t\t :{simpleTwo.arrInt[0]}");
Console.WriteLine($"string :{simple.arrString[0]}\t\t :{simpleTwo.arrString[0]}");
}
}
여기 서 우 리 는 이 실행 결 과 를 보 았 습 니 다.값 유형 이 든 인용 유형 이 든 복사 본 대상 을 수정 한 후에 원래 대상 의 값 에 영향 을 주지 않 았 습 니 다.이것 이 바로 딥 카피 의 특징 이다.
총결산
우 리 는 얕 은 복사 와 깊 은 복사 본 을 보고 자세히 돌 아 봤 다.얕 은 복사 본 은 대상 의 필드 를 새로운 대상 에 복사 합 니 다.그러나 새로운 대상 을 수정 할 때 값 형식 과 string 형식의 필드 는 원래 대상 의 필드 에 영향 을 주지 않 습 니 다.인용 유형 은 string 형식 을 제외 하고 원래 대상 의 값 에 영향 을 줍 니 다.깊 은 복사 도 대상 의 필드 를 새로운 대상 에 복사 하지만 값 유형 이 든 인용 유형의 변화 든 원래 대상 의 값 에 영향 을 주지 않 습 니 다.깊 은 복사 본 은 원래 의 대상 을 다시 만 들 고 복사 본 대상 에 복사 하기 때문이다.
자,이상 이 이 글 의 모든 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가 치 를 가지 기 를 바 랍 니 다.여러분 의 저희 에 대한 지지 에 감 사 드 립 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
C#Task를 사용하여 비동기식 작업을 수행하는 방법라인이 완성된 후에 이 라인을 다시 시작할 수 없습니다.반대로 조인(Join)만 결합할 수 있습니다 (프로세스가 현재 라인을 막습니다). 임무는 조합할 수 있는 것이다. 연장을 사용하여 그것들을 한데 연결시키는 것이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.