Сообщений 0 Оценка 48 Оценить |
А. Это сложный вопрос. Все зависит от того, насколько копия должна быть копией. :)
Если речь идет о поверхностной копии (то есть когда копируется только содержимое объекта, но все ссылки, содержащиеся в объекте, остаются теми же), то достаточно в своем классе реализовать метод Clone, в котором вызвать защищенный метод MemberwiseClone(). Однако тут есть две проблемы:
1. Может понадобиться глубокая копия.
2. Скорость MemberwiseClone().
ПРИМЕЧАНИЕ Структуры копируются присвоением, так что тут речь идет о ссылочных объектах. |
Обе проблемы можно решить написанием метода клонирования вручную (например, рекурсивно вызывая написанные вручную методы клонирования, которые производят почленное клонирование). Но это довольно трудоемко. Если классов 1-5, это еще ничего, но если их сотни...
Поверхностное клонирование можно также реализовать, если все члены данных описать в структуре, и включать в состав класса эту структуру, а не отдельные члены:
struct Data { publicint _i; publicstring _s; } class A { public A() { } public A(int i, string s) { _data._i = i; _data._s = s; } private Data _data; publicint iProp { get { return _data._i; } set { _data._i = value; } } publicstring sProp { get { return _data._s; } set { _data._s = value; } } public A Clone() { A a = new A(); // Код клонирования [b]a._data = this._data;[/b] return a; } publicoverridestring ToString() { return"iProp = " + iProp + "; sProp = " + sProp + ";"; } } class Program { staticvoid Main(string[] args) { A a1 = new A(1, "test"); Console.WriteLine("a1 = " + a1); A a2 = a1.Clone(); Console.WriteLine("a2 = " + a2); } } |
Такой подход выглядит довольно экстравагантно, но при большом количестве членов позволяет сильно облегчить ручное кодирование.
Если же нужно клонировать все объекты, на которые ссылается клонируемый, т.е. производить глубокое клонирование, то нужно или вызвать клонирование рекурсивно для всех не примитивных подобъектов, или производить сериализацию и десериализацию объекта. Первый случай требует большого объема кодирования, второй требует, чтобы все объекты были сериализуемы, и значительно (скорее всего, на пару порядков) медленнее (сериализация в .NET далека от идеала).
В общем, если код клонирования нужно создать для большого количества классов, все довольно грустно. Однако есть одно универсальное решение. Код клонирования можно генерировать автоматически на базе информации о типах объекта. Путей тут три:
A. Вот очень простое решение.
using System; using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms; class TestForm : Form { staticvoid Main() { Application.Run(new TestForm()); } private TestForm() { Text = "TestForm"; Button pb = new Button(); pb.Text = "Print"; pb.Location = new Point(10, 10); pb.Click += new EventHandler(pb_Click); Controls.Add(pb); Button cb = new Button(); cb.Text = "Close"; cb.Location = new Point(120, 10); cb.Click += new EventHandler(cb_Click); Controls.Add(cb); PropertyGrid pg = new PropertyGrid(); pg.SelectedObject = pb; pg.Location = new Point(10, 50); Controls.Add(pg); } privatevoid cb_Click(object sender, EventArgs e) { Close(); } [Flags] privateenum DrawingOptions { PRF_CHECKVISIBLE = 0x00000001, PRF_NONCLIENT = 0x00000002, PRF_CLIENT = 0x00000004, PRF_ERASEBKGND = 0x00000008, PRF_CHILDREN = 0x00000010, PRF_OWNED = 0x00000020 } privateconstint WM_PRINT = 0x0317; privateconstint WM_PRINTCLIENT = 0x0318; [DllImport("user32.dll")] privatestaticexternint SendMessage(IntPtr hWnd, int msg, IntPtr dc, DrawingOptions opts); privatevoid pb_Click(object sender, EventArgs e) { using (Bitmap bm = new Bitmap(Width + 2, Height + 2)) using (Graphics g = Graphics.FromImage(bm)) { IntPtr dc = g.GetHdc(); try { SendMessage(Handle, WM_PRINT, dc, DrawingOptions.PRF_CHILDREN | DrawingOptions.PRF_CLIENT | DrawingOptions.PRF_NONCLIENT); } finally { g.ReleaseHdc(dc); } bm.Save("bm.png"); } } } |
Сообщений 0 Оценка 48 Оценить |