카피

17728 단어 C#
c#에서 유형은 값 유형과 인용 유형으로 나뉜다. 값 유형의 대상 부여는 그 자체가 부여된 자신의 부본이고 인용 유형 부여는 무더기의 메모리를 가리킨다. 만약에 우리가 이 주소를 부여하고 싶지 않고 대상을 부여하려면 어떻게 해야 하는가?먼저 복사는 얕은 표 복사와 깊은 표 복사로 나뉘는데, 얕은 표 복사는 원시 대상과 같은 유형, 값 유형 필드와 같은 새로운 실례를 얻을 수 있다는 것을 알아야 한다.그러나 필드가 인용 형식이라면 인용이 아닌 대상을 복사합니다.인용 필드의 대상도 복사하려면 깊은 복사라고 부른다.복사를 실현하기 위해 본고는 다음과 같은 몇 가지 방법을 총결하였다.
1. 우선 가장 멍청한 방법이다. 전설의'인공 복사'는 인용된 모든 값 대상과 값 특징을 가진string 대상을 일일이 새로운 대상에게 부여하는 것이다. 이런 방식은 코드량이 너무 많고 유지하기가 상당히 번거롭기 때문에 사용하지 않으면 안 된다.
2.System.Object는 '얕은 표' 복사를 위한 보호 방법인 MemberwiseClone을 제공합니다.이 방법은 '보호됨' 단계로 표시되어 있기 때문에, 계승 클래스나 이 클래스 내부에서만 접근할 수 있습니다.
 public class A

    {

        public string rr { get; set; }

        public string tt { get; set; }





        public A ShallowCopy()

        {

            return (A)this.MemberwiseClone();

        }



    }

3. 서열화와 반서열화 방식을 사용한다. 이런 방식은 깊이 있는 복사를 실현할 수 있지만 모기를 잡는 냄새가 난다. 또한 밖에서 인용할 때 만들어진 메모리스트림 흐름을 닫는 것을 반드시 기억해야 한다.
 public static object Clone(object o,out MemoryStream ms)

        {

            BinaryFormatter bf = new BinaryFormatter();

           

            ms = new MemoryStream();

            bf.Serialize(ms,o);

            ms.Seek(0, SeekOrigin.Begin);



            return bf.Deserialize(ms);

        }

4. 한 외국인이 쓴 블로그에서http://www.codeproject.com/Articles/3441/Base-class-for-cloning-an-object-in-C), 반사하는 방법으로 이 문제를 해결했다.그는 BaseObject 클래스를 썼는데 만약에 우리가 이 클래스를 계승하면 깊이 있는 복사를 실현할 수 있다. 다음은 그의 실현 방법이다.
ICloneable 인터페이스를 실현하는 기본 행위를 가진 추상적인 클래스를 만듭니다. 기본 행위란 클래스의 모든 필드를 복사하기 위해 다음 라이브러리 함수를 사용합니다.
1. 클래스의 모든 필드를 옮겨다니며 ICloneable 인터페이스를 지원하는지 확인합니다.
2. ICloneable 인터페이스가 지원되지 않으면 다음 규칙에 따라 설정합니다. 즉, 필드가 값 유형이면 복사하고 인용 유형이면 복사 필드는 대상을 가리킨다.
3. ICloneable를 지원할 경우 클론 객체의 복제 방법을 사용하여 설정합니다.
4. 필드가 IEnumerable 인터페이스를 지원한다면 IList나 IDirectionary 인터페이스를 지원하는지 확인하고 지원하면 ICloneable 인터페이스를 지원하는지 반복해서 집합합니다.
우리가 해야 할 일은 모든 필드가 ICloneable 인터페이스를 지원하도록 하는 것이다.
다음은 테스트 결과입니다.
public class MyClass : BaseObject

{

    public string myStr =”test”;

    public int id;

}



public class MyContainer : BaseObject

{

    public string name = “test2”;

    public MyClass[] myArray= new MyClass[5];



    public class MyContainer()

    {

        for(int i=0 ; i<5 ; i++)

        {

             this.myArray[I] = new MyClass();

        }

    }

}
static void Main(string[] args)

{

    MyContainer con1 = new MyContainer();

    MyContainer con2 = (MyContainer)con1.Clone();



   con2.myArray[0].id = 5;

}

con2에서 MyClass 실례에서 첫 번째 요소는 5로 바뀌었지만 con1은 변하지 않았다. 즉, 깊은 복사를 실현했다.
BaseObject의 구현:
/// <summary>

/// BaseObject class is an abstract class for you to derive from.

/// Every class that will be dirived from this class will support the 

/// Clone method automaticly.<br>

/// The class implements the interface ICloneable and there 

/// for every object that will be derived <br>

/// from this object will support the ICloneable interface as well.

/// </summary>



public abstract class BaseObject : ICloneable

{

    /// <summary>

    /// Clone the object, and returning a reference to a cloned object.

    /// </summary>

    /// <returns>Reference to the new cloned 

    /// object.</returns>

    public object Clone()

    {

        //First we create an instance of this specific type.

        object newObject  = Activator.CreateInstance( this.GetType() );



        //We get the array of fields for the new type instance.

        FieldInfo[] fields = newObject.GetType().GetFields();



        int i = 0;



        foreach( FieldInfo fi in this.GetType().GetFields() )

        {

            //We query if the fiels support the ICloneable interface.

            Type ICloneType = fi.FieldType.

                        GetInterface( "ICloneable" , true );



            if( ICloneType != null )

            {

                //Getting the ICloneable interface from the object.

                ICloneable IClone = (ICloneable)fi.GetValue(this);



                //We use the clone method to set the new value to the field.

                fields[i].SetValue( newObject , IClone.Clone() );

            }

            else

            {

                // If the field doesn't support the ICloneable 

                // interface then just set it.

                fields[i].SetValue( newObject , fi.GetValue(this) );

            }



            //Now we check if the object support the 

            //IEnumerable interface, so if it does

            //we need to enumerate all its items and check if 

            //they support the ICloneable interface.

            Type IEnumerableType = fi.FieldType.GetInterface

                            ( "IEnumerable" , true );

            if( IEnumerableType != null )

            {

                //Get the IEnumerable interface from the field.

                IEnumerable IEnum = (IEnumerable)fi.GetValue(this);



                //This version support the IList and the 

                //IDictionary interfaces to iterate on collections.

                Type IListType = fields[i].FieldType.GetInterface

                                    ( "IList" , true );

                Type IDicType = fields[i].FieldType.GetInterface

                                    ( "IDictionary" , true );



                int j = 0;

                if( IListType != null )

                {

                    //Getting the IList interface.

                    IList list = (IList)fields[i].GetValue(newObject);



                    foreach( object obj in IEnum )

                    {

                        //Checking to see if the current item 

                        //support the ICloneable interface.

                        ICloneType = obj.GetType().

                            GetInterface( "ICloneable" , true );

                        

                        if( ICloneType != null )

                        {

                            //If it does support the ICloneable interface, 

                            //we use it to set the clone of

                            //the object in the list.

                            ICloneable clone = (ICloneable)obj;



                            list[j] = clone.Clone();

                        }



                        //NOTE: If the item in the list is not 

                        //support the ICloneable interface then in the 

                        //cloned list this item will be the same 

                        //item as in the original list

                        //(as long as this type is a reference type).



                        j++;

                    }

                }

                else if( IDicType != null )

                {

                    //Getting the dictionary interface.

                    IDictionary dic = (IDictionary)fields[i].

                                        GetValue(newObject);

                    j = 0;

                    

                    foreach( DictionaryEntry de in IEnum )

                    {

                        //Checking to see if the item 

                        //support the ICloneable interface.

                        ICloneType = de.Value.GetType().

                            GetInterface( "ICloneable" , true );



                        if( ICloneType != null )

                        {

                            ICloneable clone = (ICloneable)de.Value;



                            dic[de.Key] = clone.Clone();

                        }

                        j++;

                    }

                }

            }

            i++;

        }

        return newObject;

    }

}

 
 
 
 
 
 
 

좋은 웹페이지 즐겨찾기