Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Копирование объектов в C#

6.2K
19 ноября 2006 года
abdyla_v
40 / / 02.02.2006
Имеем объект класа. Нада получить копию этого объекта а не ссылку на него !!! Тоесть при изменении первого второй должен оставатся прежним!!! Посоветовали использовать интерфейс ICloneable. Ничего не вышло. Помогите чем можете (желательно кодом чем по проще) . Очень-очень надо !!!
Заранее благодарен !!!
242
19 ноября 2006 года
Оlga
2.2K / / 04.02.2006
ты можешь сам написать конструктор, который принимает как параметр объект, копию которого ты хочешь сделать. например у тебя есть класс Worker:
Код:
class Worker{
string firstName;
string lastName;
int age;
 
  public Worker(string fname, string lname, int age)
  {
     this.firstName = fname;
     this.lastName = lname;
     this.age = age;
  }
 
   public Worker(Worker ob)
  {
     this.firstName = ob.firstName;
     this.lastName = ob.lastName.;
     this.age = ob.age;
   }
 
     //...................
}

 
Код:
public static void Main()
{
     Worker ob1 = new Worker("Sara", "Fridman", 25);
     Worker ob2 = new Worker(ob1); [COLOR=green]//создали копию ob1[/COLOR]
 }

}
713
20 ноября 2006 года
Ap0k
360 / / 13.03.2006
Object.MemberwiseClone Method (System)
Код:
using System;

class MyBaseClass {
   public static string CompanyName = "My Company";
   public int age;
   public string name;
}

class MyDerivedClass: MyBaseClass {

   static void Main() {
   
   // Creates an instance of MyDerivedClass and assign values to its fields.
   MyDerivedClass m1 = new MyDerivedClass();
   m1.age = 42;
   m1.name = "Sam";

   // Performs a shallow copy of m1 and assign it to m2.
   MyDerivedClass m2 = (MyDerivedClass) m1.MemberwiseClone();
   }
}
273
21 ноября 2006 года
3A3-968M
1.2K / / 22.12.2005
Смотря в каком контексте тебе нужно использовать класс. Если ты создашь структуру (т.е. неявный наследник от ValueType), то переменной такого класса всегда будет передаваться копия (т.е. передача по значению). Интерфейс ICloneable позволяет управлять процессом копирования. Копирование бывает двух типов - глубокое и поверхностное. При глубоком создаётся абсолютно отдельная копия, при поверхностном создаётся копия класса, но она содержит ссылки на те же объекты что и оригинал. Метод MemberwiseClone осуществляет поверхностное копирование.
Для создания поверхностных копий можно использовать копирующий конструктор, как привела OlgaKr или вот эту функцию:
 
Код:
[SIZE=2][COLOR=#0000ff][FONT=Courier New]static [/FONT][/COLOR][/SIZE][SIZE=2][FONT=Courier New]T CreateShallowCopy<T>(T o)[/FONT][/SIZE]
[SIZE=2][FONT=Courier New]{[/FONT][/SIZE]
[FONT=Courier New][SIZE=2][COLOR=#008080] MethodInfo[/COLOR][/SIZE][/FONT][SIZE=2][FONT=Courier New] memberwiseClone = o.GetType().[/FONT][/SIZE]
[SIZE=2][FONT=Courier New]  GetMethod([/FONT][/SIZE][FONT=Courier New][SIZE=2][COLOR=#800000]"MemberwiseClone"[/COLOR][/SIZE][SIZE=2], [/SIZE][SIZE=2][COLOR=#008080]BindingFlags[/COLOR][/SIZE][SIZE=2].Instance | [/SIZE][SIZE=2][COLOR=#008080]BindingFlags[/COLOR][/SIZE][/FONT][SIZE=2][FONT=Courier New].NonPublic);[/FONT][/SIZE]
[FONT=Courier New][SIZE=2][COLOR=#0000ff] return [/COLOR][/SIZE][SIZE=2](T)memberwiseClone.Invoke(o, [/SIZE][SIZE=2][COLOR=#0000ff]null[/COLOR][/SIZE][/FONT][SIZE=2][FONT=Courier New]);[/FONT][/SIZE]
[SIZE=2][FONT=Courier New]}[/FONT][/SIZE]

Для создания глубоких копий нужно использовать интерфейс ICloneable, и реализовывать копирование вручную.
Вот, я написал метод, который производит глубокое копирование и подходит для любых объектов:
 
Код:
[SIZE=2][COLOR=#0000ff][FONT=Courier New]static [/FONT][/COLOR][/SIZE][SIZE=2][FONT=Courier New]T CreateDeepCopy<T>(T o)[/FONT][/SIZE]
[SIZE=2][FONT=Courier New]{[/FONT][/SIZE]
[SIZE=2][FONT=Courier New] T copy = CreateShallowCopy(o);[/FONT][/SIZE]
[FONT=Courier New][SIZE=2][COLOR=#0000ff] foreach[/COLOR][/SIZE][SIZE=2]([/SIZE][SIZE=2][COLOR=#008080]FieldInfo[/COLOR][/SIZE][SIZE=2] f [/SIZE][SIZE=2][COLOR=#0000ff]in [/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]typeof[/COLOR][/SIZE][SIZE=2](T).GetFields([/SIZE][SIZE=2][COLOR=#008080]BindingFlags[/COLOR][/SIZE][SIZE=2].Instance | [/SIZE][SIZE=2][COLOR=#008080]BindingFlags[/COLOR][/SIZE][SIZE=2].NonPublic | [/SIZE][SIZE=2][COLOR=#008080]BindingFlags[/COLOR][/SIZE][/FONT][SIZE=2][FONT=Courier New].Public))[/FONT][/SIZE]
[SIZE=2][FONT=Courier New] {[/FONT][/SIZE]
[FONT=Courier New][SIZE=2][COLOR=#0000ff]   object[/COLOR][/SIZE][/FONT][SIZE=2][FONT=Courier New] original = f.GetValue(o);[/FONT][/SIZE]
[SIZE=2][FONT=Courier New]   f.SetValue(copy, CreateDeepCopy(original));[/FONT][/SIZE]
[SIZE=2][FONT=Courier New] }[/FONT][/SIZE]
[FONT=Courier New][SIZE=2][COLOR=#0000ff] return[/COLOR][/SIZE][/FONT][SIZE=2][FONT=Courier New] copy;[/FONT][/SIZE]
[SIZE=2][FONT=Courier New]}[/FONT][/SIZE]
842
21 марта 2010 года
sigmov
301 / / 16.09.2008
Заново открываю тему, так как она вновь актуальна )))
Очень нужно полное копирование объектов с большой иерархией вложений ))).
Цитата: 3A3-968M
Вот, я написал метод, который производит глубокое копирование и подходит для любых объектов:


К сожалению вообще не работает. ((((

Причины, которые мне удалось выявить:
1) "typeof(T).GetFields(" - очевидно что уже на втором шаге "object original = f.GetValue(o); f.SetValue(copy, CreateDeepCopy(original));" типом T будет являться тип object, что естественно нас не устраивает, ибо на самом деле это возможно замаскированный тип с кучей вложений....
2) Array.memberwiseClone() не запускает memberwiseClone() для самих элементов массива (((
3) Не у всех классов метод .memberwiseClone() не является перегруженным ( пример - StreamReader )
4) Специфика типа string, не позволяет скопировать его простым .memberwiseClone()
5) Если одно из вложенных полей == null вылезет ошибка

5
21 марта 2010 года
hardcase
4.5K / / 09.08.2005
Цитата: sigmov
Заново открываю тему, так как она вновь актуальна )))


Вот тут было дело. Но это все очень медленно, код генерировать все же эффективнее.

842
21 марта 2010 года
sigmov
301 / / 16.09.2008
Цитата: hardcase
Вот тут было дело. Но это все очень медленно, код генерировать все же эффективнее.



Очень интересно......
Я уже признаться свой код как раз накатал, причем в похожем ключе....
Вообщем добавив некоторые идеи, получил следующее:
Улучшения:
1) MemberwiseClone собирается как делегат, что работает намного быстрее Invoke()
2) Обработка 1,2,3х мерных массивов более быстрая

Код:
public static class Clonner
    {
        static Func<object, object> MemberwiseClone =
            Delegate.CreateDelegate
            (
                typeof(Func<object, object>),
                typeof(object).GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic)
            )
            as Func<object, object>;

        public static object DeepClone(this object obj)
        {
            if (object.ReferenceEquals(obj, null)) return null; //Если объект ~ null, то и клон его - null
            else
            {
                if (obj is string) return string.Copy(obj as string);    //если тип - строка то производим "хитрое" копирование
                else if (obj is Array)                                                          //Если объект - массив, необходимо поочередно глубококлонировать его элементы
                {
                    Array array = (obj as Array).Clone() as Array;  //Клонируем массив
                    switch (array.Rank)                             //Для ускорения различаем массивы по числу размерностей
                    {
                        case 1: // T[]
                            {
                                int bi = array.GetLowerBound(0), ei = array.GetUpperBound(0) + 1;
                                for (int i = bi; i < ei; i++)
                                    array.SetValue(DeepClone(array.GetValue(i)), i);
                                break;
                            }
                        case 2: // T[,]
                            {
                                int bi = array.GetLowerBound(0), ei = array.GetUpperBound(0) + 1;
                                int bj = array.GetLowerBound(1), ej = array.GetUpperBound(1) + 1;
                                for (int i = bi; i < ei; i++)
                                    for (int j = bj; j < ej; j++)
                                        array.SetValue(DeepClone(array.GetValue(i, j)), i, j);
                                break;
                            }
                        case 3: // T[,,]
                            {
                                int bi = array.GetLowerBound(0), ei = array.GetUpperBound(0) + 1;
                                int bj = array.GetLowerBound(1), ej = array.GetUpperBound(1) + 1;
                                int bk = array.GetLowerBound(2), ek = array.GetUpperBound(2) + 1;
                                for (int i = bi; i < ei; i++)
                                    for (int j = bj; j < ej; j++)
                                        for (int k = bk; k < ek; k++)
                                            array.SetValue(DeepClone(array.GetValue(i, j, k)), i, j, k);
                                break;
                            }
                        default: // T[,,...,] - более трех размерностей
                            {
                                //для прохода по всем индексам используем специальный индекс-итератор
                                foreach (var indx in new Indexer(array)) array.SetValue(DeepClone(array.GetValue(indx)), indx);
                                break;
                            }
                    }
                    return array;
                }
                else // объект не null, не строка и не массив
                {
                    Type tyobj = obj.GetType();         //узнаем тип объекта
                    if (tyobj.IsPrimitive) return obj;  //если тип является примитивом (int, double и т.п.) то нет смысла копаться в его внутренностях
                    else
                    {
                        object clone = MemberwiseClone(obj);
                        //глубококлонируем все поля объекта
                        foreach (var field in tyobj.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
                            field.SetValue(clone, DeepClone(field.GetValue(clone)));
                        return clone;
                    }
                }
            }
        }
    }
    internal struct Indexer : IEnumerable<int[]>
    {
        public int rank;
        public int[] LoverBownds;
        public int[] UpperBownds;

        public Indexer(Array array)
        {
            this.rank = array.Rank;
            this.LoverBownds = new int[rank];
            this.UpperBownds = new int[rank];
            for (int i = 0; i < this.rank; i++)
            {
                this.LoverBownds = array.GetLowerBound(i);
                this.UpperBownds = array.GetUpperBound(i);
            }
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
        public IEnumerator<int[]> GetEnumerator()
        {
            int[] CurrentIndexs = this.LoverBownds.Clone() as int[];
            for (int i = this.rank - 2; ; )
            {
                for (; ++i < this.rank; )
                    CurrentIndexs = this.LoverBownds;
                for (--i; CurrentIndexs <= this.UpperBownds; CurrentIndexs++)
                    yield return CurrentIndexs;
                for (; --i != -1 && CurrentIndexs == this.UpperBownds; ) ;

                if (i < 0) break;
                else CurrentIndexs++;
            }
        }
        //public override string ToString()
        //{
        //    StringBuilder sb = new StringBuilder(16);
        //    sb.Append("[ { ");
        //    foreach (var low in this.LoverBownds) { sb.Append(low); sb.Append(' '); }
        //    sb.Append("} <= { ");
        //    foreach (var up in this.UpperBownds) { sb.Append(up); sb.Append(' '); }
        //    sb.Append("} ]");
        //    return sb.ToString();
        //}
    }
58K
25 марта 2010 года
beespace
5 / / 24.03.2010
Код:
using System;

//Использование интерфейса ICloneable

namespace ProICloneable
{
    class X
    {
        public int a;
        public X(int x) { a = x;}
    }

    class Test:ICloneable
    {
        public X o;
        public int b;
        public Test(int x, int y)
        {
            o = new X(x);
            b = y;
        }
        public void show(string name)
        {
            Console.WriteLine("Объект " + name + "-");
            Console.WriteLine("o.a:{0}, b:{1}", o.a, b);
        }
//Создает глубокую копию вызывающего
        public object Clone()
        {
            Test temp = new Test(o.a, b);
            return temp;
        }
    }

    class CloneDemo
    {
        static void Main()
        {
            Test ob1 = new Test(10, 20);
            ob1.show("ob1");
            Console.WriteLine("Объект ob2 создается объект как копия объекта ob1");
            Test ob2 = (Test)ob1.Clone();
            ob2.show("ob2");

            Console.WriteLine("ob1.o.a присвоено значение 99, ob1.b присвоено значение 88");
            ob1.o.a = 99;
            ob1.b = 88;

            ob1.show("ob1");
            ob2.show("ob2");

        }
    }
}
5
25 марта 2010 года
hardcase
4.5K / / 09.08.2005
Цитата: beespace
 
Код:
....


И что вы хотели этим сказать?

58K
25 марта 2010 года
beespace
5 / / 24.03.2010
Цитата: hardcase
И что вы хотели этим сказать?


что разве не видно код программы?

5
25 марта 2010 года
hardcase
4.5K / / 09.08.2005
Цитата: beespace
что разве не видно код программы?


Код программы видно, но я больше ценю слова изложенные на русском языке.

58K
31 марта 2010 года
beespace
5 / / 24.03.2010
Цитата: hardcase
Код программы видно, но я больше ценю слова изложенные на русском языке.


странный подход к программированию....
скажите, что вам изложить на русском языке?

5
31 марта 2010 года
hardcase
4.5K / / 09.08.2005
Цитата: beespace
странный подход к программированию....
скажите, что вам изложить на русском языке?


Ваш способ копирования произвольного графа объектов. Врукопашную реализовать IClonable во всех классах - это же охренеть ведь можно ;)

842
31 марта 2010 года
sigmov
301 / / 16.09.2008
Цитата: hardcase
Ваш способ копирования произвольного графа объектов. Врукопашную реализовать IClonable во всех классах - это же охренеть ведь можно ;)



Это еще и невозможно, ибо есть классы NET для которых данная поцедура не предусмотрена...

Цитата: beespace
что разве не видно код программы?



Видно, но смысл какой в нем? - наследовать все от ICloneable?

Ну тогда такая задачка сразу на ум приходит:

 
Код:
public class TwoList
    {
        object[] myObgects;
        List<object> myItems;
    }

Сможете для него реализовать "глубокое" копирование?
842
31 марта 2010 года
sigmov
301 / / 16.09.2008
Цитата: sigmov
Это еще и невозможно, ибо есть классы NET для которых данная поцедура не предусмотрена...



Видно, но смысл какой в нем? - наследовать все от ICloneable?

Ну тогда такая задачка сразу на ум приходит:
 
Код:
public class TwoList
    {
        object[] myObgects;
        List<object> myItems;
    }

Сможете для этого класса реализовать "глубокое" копирование?



Здесь по шла речь об УНИВЕРСАЛЬНОМ методе.

61K
10 июня 2010 года
serg698
2 / / 10.06.2010
Есть хороший вариант использовать сериализацию, минус пожалуй необходимость поддержки сериализуемости у исходного объекта и всех вложенных, а так:
Код:
public static object DeepClone(object obj) {
            if(obj == null) { return null; }
            object result = null;
            using(MemoryStream ms = new MemoryStream()) {
                BinaryFormatter bf = new BinaryFormatter();
                bf.Serialize(ms, obj);
                ms.Position = 0;
                result = bf.Deserialize(ms);
            }
            return result;
        }

..........
TwoList copyObject = (TwoList)DeepClone(sourceObject);
Метод получается довольно универсальный
6.2K
10 июня 2010 года
abdyla_v
40 / / 02.02.2006
Цитата: serg698

..........
TwoList copyObject = (TwoList)DeepClone(sourceObject);
Метод получается довольно универсальный


А как с быстродействием в данном случаи?

61K
11 июня 2010 года
serg698
2 / / 10.06.2010
Цитата:
А как с быстродействием в данном случаи?



Честно говоря быстродействие не тестировал, прибег к этому методу по причинам того что в проекте необходимо было клонировать объекты, с большой ссылочной вложенностью, и интерфейс ICloneable реализовывать вниз совсем было не интересно и не оправдано. А вообще метод прекрасно справляется на объектах весом до 100 мб. Я думаю что можно повысить эффективность если объектами реализовать интерфейс ISerializable, я же просто приписал аттрибут [Serialize].. хотя это только догадки

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог