Копирование объектов в C#
Заранее благодарен !!!
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;
}
//...................
}
{
Worker ob1 = new Worker("Sara", "Fridman", 25);
Worker ob2 = new Worker(ob1); [COLOR=green]//создали копию ob1[/COLOR]
}
}
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();
}
}
Для создания поверхностных копий можно использовать копирующий конструктор, как привела OlgaKr или вот эту функцию:
[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][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]
Очень нужно полное копирование объектов с большой иерархией вложений ))).
К сожалению вообще не работает. ((((
Причины, которые мне удалось выявить:
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 вылезет ошибка
Очень интересно......
Я уже признаться свой код как раз накатал, причем в похожем ключе....
Вообщем добавив некоторые идеи, получил следующее:
Улучшения:
1) MemberwiseClone собирается как делегат, что работает намного быстрее Invoke()
2) Обработка 1,2,3х мерных массивов более быстрая
{
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();
//}
}
//Использование интерфейса 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");
}
}
}
И что вы хотели этим сказать?
что разве не видно код программы?
Код программы видно, но я больше ценю слова изложенные на русском языке.
странный подход к программированию....
скажите, что вам изложить на русском языке?
скажите, что вам изложить на русском языке?
Ваш способ копирования произвольного графа объектов. Врукопашную реализовать IClonable во всех классах - это же охренеть ведь можно ;)
Это еще и невозможно, ибо есть классы NET для которых данная поцедура не предусмотрена...
Видно, но смысл какой в нем? - наследовать все от ICloneable?
Ну тогда такая задачка сразу на ум приходит:
{
object[] myObgects;
List<object> myItems;
}
Сможете для него реализовать "глубокое" копирование?
Видно, но смысл какой в нем? - наследовать все от ICloneable?
Ну тогда такая задачка сразу на ум приходит:
{
object[] myObgects;
List<object> myItems;
}
Сможете для этого класса реализовать "глубокое" копирование?
Здесь по шла речь об УНИВЕРСАЛЬНОМ методе.
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);
Метод получается довольно универсальный
..........
TwoList copyObject = (TwoList)DeepClone(sourceObject);
Метод получается довольно универсальный
А как с быстродействием в данном случаи?
Честно говоря быстродействие не тестировал, прибег к этому методу по причинам того что в проекте необходимо было клонировать объекты, с большой ссылочной вложенностью, и интерфейс ICloneable реализовывать вниз совсем было не интересно и не оправдано. А вообще метод прекрасно справляется на объектах весом до 100 мб. Я думаю что можно повысить эффективность если объектами реализовать интерфейс ISerializable, я же просто приписал аттрибут [Serialize].. хотя это только догадки