2011-12-25 6 views
14

나는 기본 클래스를 가지고C# 상속. 기본 클래스에서 파생 된 클래스는

public class A 
{ 
    public string s1; 
    public string s2; 
} 
나는 또한 파생 클래스가

:

public class B : A 
{ 
    public string s3; 
} 

내 프로그램은 클래스 A의 인스턴스를 생성 가정을

A aClassInstance = new A(); 

일부 매개 변수가 설정되었습니다 :

aClassInstance.s1 = "string 1"; 
aClassInstance.s2 = "string 2"; 
이 시점에서

내가 클래스 B의 인스턴스를 생성하고 싶습니다하지만 이미 클래스 A의 내 인스턴스의 값을 가지고 B 싶습니다

이 작동하지 않았다 :

public B bClassInstance = new B(): 
bClassInstance = (B)aClassInstance; 

- BU

만든 클래스 A. 내에서 복제 방법은

public B cloneA() {  
    A a = new A(); 
    a = (A)this.MemberwiseClone() 
    return(B)a; 
} 

은 VS 코드는 위의 둘을 취 어느 쪽이 DID t I 런타임 오류가

+2

복제 할 때 특히 클래스에 가변 참조 유형의 필드가있는 경우 특히주의하십시오. 깊은 복제본이나 얕은 복제본을 원하면 결정하고 문서화하십시오. – TrueWill

+1

오른쪽. 이 특정 클래스에는 참조가 없으므로 얕은 복제가 작동합니다. 관심있는 모든 사람들을 위해 여기에서 얕은 복제와 깊은 복제에 대한 좋은 게시물을 찾았습니다. http://itpksingh.blogspot.com/2009/08/shallow-copyingdeep-copyingobject.html – Sam

+0

ValueInjector를 사용하여 솔루션을 찾았습니다. StackOverFlow는 아직 "내 질문에 대답"을 허용하지 않습니다. 일단 그렇게되면 전체 세부 정보를 게시합니다. – Sam

답변

21

기본 문제는 B (이는 A 유형의 속성이 포함됨) 유형의 인스턴스를 만들어야한다는 것입니다. A 인스턴스 복제 방법은 작동하지 않습니다. 이는 A 유형의 인스턴스를 제공하기 때문에 B으로 변환 할 수 없기 때문입니다.

클래스 A와 B에 대한 생성자는 A 유형의 매개 변수를 사용합니다. 클래스 B의 생성자는 값을 기본 클래스 A로 전달합니다.클래스 A의 생성자는 자체에 필드를 복사하는 방법을 알고 : 변경하고 싶지 않을 때

A a = new A(); 
a.s1 = "..."; 

B b = new B(a); 

편집

:

class A { 
    public A(A copyMe) { 
     s1 = copyMe.s1; 
     ... 
    } 

class B : A { 

    public B(A aInstance) : base(aInstance) { 
    } 

} 

이이 방법을 사용하여 새 필드 또는 소품을 추가 할 때 A의 생성자를 사용하면 반사를 사용하여 속성을 복사 할 수 있습니다.

public A (A copyMe) { 
    Type t = copyMe.GetType(); 
    foreach (FieldInfo fieldInf in t.GetFields()) 
    { 
     fieldInf.SetValue(this, fieldInf.GetValue(copyMe)); 
    } 
    foreach (PropertyInfo propInf in t.GetProperties()) 
    { 
     propInf.SetValue(this, propInf.GetValue(copyMe)); 
    } 
} 

내가 코드를 시도 havn't는하지만, 요점은 명확하게해야한다 : 어느 복사 할, 또는 A 단지 모든 소품/필드를 복사 무엇을 장식하는 사용자 정의 속성을 사용합니다.

+0

각 구성원을 개별적으로 복사 할 필요가 없도록이를 업그레이드하려고합니다. class A { public A (copyMe) { s1 = copyMe.s1; (A) copyMe.MemberwiseClone()은 내가 필요한 호출 A의 얕은 복제본을 반환해야합니다. 이제 우리가해야 할 일은 B 생성자로 다시 전달하는 것입니다 ... 질문은 방법입니다. 불행하게도 우리는이 작업을 수행 할 수 없습니다 클래스 A { 공용 A 주택 (A copyMe) { 이 = (A) copyMe.MemberwiseClone() } } ... } – Sam

+1

@Sam : 문제는 유형 B의 객체를 만들어야한다는 것입니다. A가 B의 일부이기 때문에 유형 A에 속하는 새 B 인스턴스의 속성 설정 방법을 찾아야합니다. * 클론 A * 접근 방식은 작동하지 않을 것입니다. 그 이유는 이것이 타입 B의 인스턴스를 필요로하는 타입 A의 인스턴스를 제공하기 때문입니다! 당신이 할 수있는 일은 A.의 생성자에서 리플렉션을 사용하는 것입니다.이를 반영하기 위해 답변을 업데이트 할 것입니다. – Jan

8

당신은 클래스 A에서 일반 복제 방법을 만들 수 있습니다 도와주세요 얻을 :

 public T Clone<T>() where T : A, new() { 
      return new T() { a = this.a, b = this.b}; 
    } 

을 또는 당신은 확장 복제 만들고 싶어 :

 public T Clone<T>() where T : A, new() { 
      var result = new T(); 
      this.CopyTo(result); 
      return result; 
    } 

    protected virtual void CopyTo(A other) { 
      other.a = this.a; 
      other.b = this.b; 
    } 

다음과 같이 사용하십시오 :

 A a = new A(); 
    // do stuff with a 
    // Create a B based on A: 
    B b = a.Clone<B>(); 

참고 : 귀하의 예에서 새로운 A() 및 MemberwiseClone은 모두 A 유형의 새 객체를 생성합니다.

직접 복사 방법을 코딩하지 않으려면 도구 AutoMapper입니다.

+0

고마워요! 이 예제에서는 a = this.a, b = this.b 등의 멤버를 모두 설정해야합니다. 클래스에 여러 멤버가있는 경우 각 멤버를 코딩하지 않으려면 어떻게해야합니까? (다른 멤버를 추가하기로 결정한 경우 복제 기능에서도 설정해야 함) – Sam

+0

리플렉션을 사용하여 모든 필드를 복사하고 복사 할 수는 있지만 경험에 따르면 더 좋을 것입니다. 직접 복사를 제어하십시오. 때로는 얕은 복사본이 필요합니다. 일부 복사본에는 깊은 복사본이 필요합니다. – GvS

+0

왜 'other = (A) this가 아닌가?MemberwiseClone();'(각 속성을 설정하는 대신) 위에서 작업하십시오. 각 속성을 설정하거나 반사를 사용하지 않으려 고합니다. – PeterX

1

GvS와 Jan의 위의 두 가지 해결 방법을 모두 들으면서 눈을 뜰 수있는 모든 것을 읽은 후 재생했습니다. 그러나 최종 결과는 Copy 메서드에서 각 멤버를 작성하지 않아도된다는 것입니다.

이유 : a) 클래스가 편집되고 다른 개체가 추가되면 복사 방법을 업데이트해야합니다. 누군가 다른 사람이 수업을 업데이트하면, 잊어 버릴 수도 있습니다.

b) 많은 회원이있을 수 있으며 할당하는 데 시간이 오래 걸릴 수 있습니다.

c) 단지 "느껴지지 않습니다". (아마 내가 매우 게으 르기 때문에).

다행히도 나는 같은 생각을 가진 유일한 사람이 아닙니다. ValueInjector를 통해 매우 쉬운 해결책을 찾았습니다. (이 게시판에서는 많은 논의가있었습니다). 당신이 포함해야 할 것입니다 분명히

을 :)의

A a = new A(); 
a.s1 = "..."; 


B b = new B(); 
b.InjectFrom(a); 

을 :

dll을 (http://valueinjecter.codeplex.com/documentation)

코드가되고 점점 후 :

using Omu.ValueInjecter; 

그리고 참조에 추가하는 것을 잊지 마십시오.

관련 문제