Модераторы: Partizan, gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Клонирование об"екта. Events. Клонировать события. 
:(
    Опции темы
lam0x7C4
  Дата 1.7.2008, 12:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 59
Регистрация: 1.6.2007
Где: Киев

Репутация: 1
Всего: 1



Всем привет!
Такая вот ситуацыя: на свой страх и риск нужно сделать метод, который может клонировать произвольный об"ект, используя рефлекшн. Клон должен иметь такие же значения значимых свойств и так же реагировать на события, как и оригинал. Все вроде бы ничего, но никак не получаться клонировать события.

   
Код

 public class Xerox // :)
    {
            // ... копирование значымих свойств.
            
            // клонирование событий
            if (cloneEvents)
            {
                foreach (EventInfo ei in obj.GetType().GetEvents())
                {
                     // вот тут то и трабл
                    MethodInfo mi = ei.GetRaiseMethod();// как получить метод(ы), что визываються при                         событии?
                    if (mi != null)
                    {
                        Delegate d = Delegate.CreateDelegate(ei.EventHandlerType, mi);
                       
                        ei.AddEventHandler(clone, d);
                    }
                }
            }

            return clone;
        }



п.с. только ради Бога, не надо тут начинать, что клонировать об"ект - ето типа нехорошо, не по фен-шую, и т.д. й т.п. Сам знаю   smile 

п.п.с. заранее пасиба.
PM MAIL ICQ   Вверх
Zakonnic
Дата 2.7.2008, 11:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 161
Регистрация: 25.4.2006

Репутация: 2
Всего: 6



Вообще-то предложеным способом вы клонируете тип, а не объект. Соответственно обработчиков в ивенты не может быть записано. Они пишутся на этапе выполнения кода, то есть создания экземпляра типа и его работы.
--------------------
...и никогда не пишите в комментариях правду
PM MAIL ICQ   Вверх
altarvic
Дата 2.7.2008, 13:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 87
Регистрация: 2.3.2007

Репутация: 1
Всего: 1



Object.MemberwiseClone ?
PM MAIL   Вверх
Ctrl
Дата 2.7.2008, 20:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 49
Регистрация: 12.2.2008
Где: Tula

Репутация: 6
Всего: 7



Интересный вопрос!!
2 Zakonnic: все нормально - человек делает то, что делает

2 altarvic: В принципе все верно:
 Object.MemberwiseClone создаст так называемую Shallow-копию твоего объекта, 
 т.е. склонирует его поля (Это важно!!!) - а так как по-большому счету эвент - это замаскированый референс на экземпляр    класса, производного от MulticastDelegate, то при клонировании этим методом в клоне мы получим ссылку на тот же экземпляр, и соответственно на те-же

Добавлено через 1 минуту и 33 секунды
обработчики все остальное

хм...  надо бы эту идею подкрепить тестами
PM MAIL ICQ   Вверх
Ctrl
Дата 2.7.2008, 20:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 49
Регистрация: 12.2.2008
Где: Tula

Репутация: 6
Всего: 7



Ага, все работает. Вот тестовое приложение (Куда брейкпоинты ставить надеюсь понятно)

Код

using System;
using NUnit.Framework;

namespace EventCloneTestApp {
    class Program {
        static void Main(string[] args) {
            DoTest();
        }
        static void DoTest() {
            TestEntity testEntyty1 = new TestEntity();
            int counter = 0;
            testEntyty1.TestEvent += delegate() {
                counter++;
            };
            TestEntity testEntyty2 = testEntyty1.Clone();
            //
            Assert.AreEqual(0, counter);   
            testEntyty2.RaiseTestEvent();             // !!!
            Assert.AreEqual(1, counter);
        }
    }
    public class TestEntity { 
        public event TestEventHandler TestEvent;
        public TestEntity Clone() {
            return MemberwiseClone() as TestEntity;
        }
        //
        protected internal void RaiseTestEvent() {
            if(TestEvent != null) TestEvent();
        }
    }
    public delegate void TestEventHandler();
}


PM MAIL ICQ   Вверх
Zakonnic
Дата 3.7.2008, 09:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 161
Регистрация: 25.4.2006

Репутация: 2
Всего: 6



Цитата(Ctrl @  2.7.2008,  20:02 Найти цитируемый пост)
все нормально - человек делает то, что делает

Человек использует рефлекшн, чтобы клонировать объект, который уже прошел инициализацию, пожил и поработал. Мембервайз клоун работает - это понятно. Вы тогда уж приведите пример, как через obj.GetType().GetEvents() и все остальное можно получить клон объекта, а не типа ;)

PS. А рефлекшном рекомендовал бы проверять объекты на принадлежность ICloneable и если что - использовать их родной метод Clone().

--------------------
...и никогда не пишите в комментариях правду
PM MAIL ICQ   Вверх
Idsa
Дата 3.7.2008, 10:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 2086
Регистрация: 5.12.2006
Где: Томск

Репутация: 14
Всего: 62



Цитата(Zakonnic @  3.7.2008,  13:39 Найти цитируемый пост)
рефлекшном рекомендовал бы проверять объекты на принадлежность ICloneable

Зачем Reflection?
Код

if (obj is ICloneable)




--------------------
Мой блог: alexidsa.blogspot.com
PM MAIL ICQ   Вверх
Ctrl
Дата 3.7.2008, 18:42 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 49
Регистрация: 12.2.2008
Где: Tula

Репутация: 6
Всего: 7



Вот пример клонирования всех "простых" евентов объекта через "obj.GetType().GetEvents() и все остальное"... эт на случай если нету у объекта реализации ICloneable или чего-то подобного. (MemberviseClone в этом случае тоже просто так не прокатит). 

Идея: для клонирования всего объекта надо дернуть клонирование всех его полей...
Такое клонирование - операция медленная но, если грамотно закешировать Reflection-вызовы ... скорость получится очень хорошая (ненамного медленнее прямого копирования полей в реализации ICloneable.Clone)

Код

using System;
using NUnit.Framework;
using System.Reflection;

namespace EventCloneTestApp {
    class Program {
        static void Main(string[] args) {
            DoTest();
        }
        static void DoTest() {
            int counter = 0;
            TestEntity testEntyty1 = new TestEntity();
            testEntyty1.TestEvent += delegate() {
                counter++;
            };
            TestEntity testEntyty2 = new TestEntity();
            ReflectionHelper.CloneAutoGeneratedEvents(testEntyty1, testEntyty2, typeof(TestEntity));
            //
            Assert.AreEqual(0, counter);
            testEntyty2.RaiseTestEvent();
            Assert.AreEqual(1, counter);
        }
    }
    public delegate void TestEventHandler();
    public class TestEntity {
        public event TestEventHandler TestEvent;
        protected internal void RaiseTestEvent() {
            if(TestEvent != null) TestEvent();
        }
        // No Clone() implementation...
    }

    public static class ReflectionHelper {
        public static void CloneAutoGeneratedEvents(object source, object target, Type type) {
            foreach(EventInfo ei in type.GetEvents()) {
                ClonePrivateField(source, target, type, ei.Name);
            }
        }
        public static void ClonePrivateField(object source, object target, Type type, string fieldName) {
            FieldInfo fieldInfo = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
            if(fieldInfo != null) {
                fieldInfo.SetValue(target, fieldInfo.GetValue(source));
            }
        }
    }
}


PM MAIL ICQ   Вверх
altarvic
Дата 4.7.2008, 07:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 87
Регистрация: 2.3.2007

Репутация: 1
Всего: 1



а если нет полей для эвентов? допустим они хранятся в хеш-таблице?
К тому же этот вариант будет работать если наименования полей совпадают с наименованием событий, (сейчас в C# так, но хз как в других языках)
В общем случае нет такого алгоритма, только частные случаи

(чем не нравится MemberwiseClone ? Все тоже самое только одной строчкой)

Код

public class ReflectionHelper
{
        public static T GetShallowCopy<T>(T obj) where T: class
        {
            Converter<object, object> _memberwiseClone = (Converter<object, object>) Delegate.CreateDelegate(typeof(Converter<object, object>), typeof(object).GetMethod("MemberwiseClone", BindingFlags.NonPublic | BindingFlags.Instance));
            return (T) _memberwiseClone(obj);
        }
}


Это сообщение отредактировал(а) altarvic - 4.7.2008, 07:54
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.0522 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.