@Ksarrik

Метод Object.MemberwiseClone() и и обработчики событий?

Добрый день, я новичок в программировании, поэтому заранее прошу прощение за возможно глупый вопрос. Недавно столкнулся с такой проблемой, имеется объект некоторого класса какой вызывает некоторое событие. Так же имеется имеется другой объект содержащий первый объект как одну из своих переменных. Как в первом так и во втором объекте был реализован интерфейс ICloneable, в котором использовался метод Object.MemberwiseClone() для копирования множества свойств-значений. Так вот: при возникновении события в объекте клоне, метод обработчик вызывался первого объект-оригинала, а не объекта-клона (как ожидалось). Решение данной проблемы не нашел, пришлось отказаться от метода Object.MemberwiseClone() и вручную переназначать значения всех переменных новому объекту -клону. Вопрос в следующем: если кто-то сталкивался с подобным, может знает решение, как сделать чтобы обработчики события копировались а не ссылались на объект оригинал?? Вот сделал пример с подобной ситуацией:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Событие_и_клонирование
{
    class Program
    {
        // Объявить тип делегата для события.
        delegate void MyEventHandler();
        // Объявить класс, содержащий событие.
        class MyEvent: ICloneable
        {
            public int number { get; set; } //Номер объекта
            public string name { get; set; } //Имя объекта
            public event MyEventHandler SomeEvent;
          // Этот метод вызывается для запуска события.
          public void OnSomeEvent()
            {
                if (SomeEvent != null)
                    SomeEvent();
            }
            public object Clone()
            {
                MyEvent newMyEvent = (MyEvent)this.MemberwiseClone();  //Метод для копирования объектов значений

                newMyEvent.name = String.Copy(name);
                return newMyEvent;
            }
        }
        //Класс содержащий событие
        class EventDemo: ICloneable
        {
            public MyEvent evt = new MyEvent();
           public EventDemo()
            {
                evt.SomeEvent += Handler; //присваиваем обработчик события
                }
            // Обработчик события.
            void Handler()
            {
                Console.WriteLine("Событие произошло в объекте: " + evt.name);
            }
            public object Clone()
            {
                EventDemo newEventDemo = (EventDemo)this.MemberwiseClone(); //Метод для копирования объектов значений

                newEventDemo.evt = (MyEvent)evt.Clone(); //Клонируем вложенный объект
                return newEventDemo;
            }
        }
            static void Main(string[] args)
        {
            //первый вариант
            ObservableCollection<EventDemo> Collect = new ObservableCollection<EventDemo>() { new EventDemo(), new EventDemo()};
            Collect[0].evt.name = "Объект 1";
            Collect[0].evt.number = 1;
            Collect[1].evt.name = "Объект 2";
            Collect[1].evt.number = 2;
            Console.WriteLine("Первый объект коллекции: " + Collect[0].evt.name+"   Номер объекта: "+ Collect[0].evt.number);
            Console.WriteLine("Второй объект коллекции: " + Collect[1].evt.name + "   Номер объекта: " + Collect[1].evt.number);
            foreach (EventDemo col in Collect)
            {
                col.evt.OnSomeEvent();
            }
            //второй вариант
            Collect = new ObservableCollection<EventDemo>() { new EventDemo(), (EventDemo)Collect[0].Clone() };
            Collect[0].evt.name = "Объект 1";
            Collect[0].evt.number = 1;
            Collect[1].evt.name = "Объект 2";
            Collect[1].evt.number = 2;
            Console.WriteLine("Первый объект коллекции: " + Collect[0].evt.name + "   Номер объекта: " + Collect[0].evt.number);
            Console.WriteLine("Второй объект коллекции: " + Collect[1].evt.name + "   Номер объекта: " + Collect[1].evt.number);
            foreach (EventDemo col in Collect)
            {
                col.evt.OnSomeEvent();
            }


            Console.ReadLine();
        }
    }
}

Выдает следующий результат:
Первый объект коллекции: Объект 1 Номер объекта: 1
Второй объект коллекции: Объект 2 Номер объекта: 2
Событие произошло в объекте: Объект 1
Событие произошло в объекте: Объект 2
Первый объект коллекции: Объект 1 Номер объекта: 1
Второй объект коллекции: Объект 2 Номер объекта: 2
Событие произошло в объекте: Объект 1
Событие произошло в объекте: Объект 1

Как видите событие происходит не в объекте 2, а в объекте 1
  • Вопрос задан
  • 754 просмотра
Решения вопроса 1
arusef
@arusef
Novice .NET dev
Метод MemberwiseClone делает неполную копию объекта (ValueType копируются по значению, а вот для ссылочных типов копируется только ссылка), поэтому во втором объекте у вас лежит ссылка на всё тот же MyEventHandler из первого объекта.
Попробуйте в методе MyEvent.Clone изменить правую строку с MemberwiseClone на просто new MyEvent(). А вот в методе EventDemo.Clone дописать evt.SomeEvent += Handler;
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы