Как написать преобразование из базового в производный?
От: imba  
Дата: 29.07.09 10:06
Оценка:
Простая вещь нужна, но не вдуплю никак, как это сделать .
Нужно написать имплисит преобразование из базового класса в производный. Для всех полей базового класса просто сделать memberwise clone, ну и пару производных полей заполнить определённым образом. Как скопировать все поля? Вариант скопировать их по одному прямо в операторе преобразования — не катит, конечно.

Поиском наткнулся на один пост, где в базовом классе определялся метод BaseClass.CloneTo<T> where T:BaseClass. Это лучший вариант?
Re: Как написать преобразование из базового в производный?
От: imba  
Дата: 29.07.09 10:26
Оценка:
I>Поиском наткнулся на один пост, где в базовом классе определялся метод BaseClass.CloneTo<T> where T:BaseClass. Это лучший вариант?

Сорри за неточность.. метод, конечно, BaseClass.CloneTo<T>(T to) where T:BaseClass.
Но в этом методе, разумеется, всё равно присваивание полей поочерёдно.
Я к тому, что MemberwiseClone не получится-таки использовать?
Re: Как написать преобразование из базового в производный?
От: imba  
Дата: 29.07.09 10:47
Оценка:
I>Нужно написать имплисит преобразование из базового класса в производный. Для всех полей базового класса просто сделать memberwise clone, ну и пару производных полей заполнить определённым образом.

Мда... оказывается, вообще "user-defined conversions to or from a base class are not allowed". Не совсем понятно, почему так.. почитать спецификацию, что ли .
Буду благодарен, если кто-нить по-человечески объяснит, почему... и как можно было бы решить первоначальную задачу, если бы они были allowed.
Re: Как написать преобразование из базового в производный?
От: Lloyd Россия  
Дата: 29.07.09 11:16
Оценка: 1 (1)
Здравствуйте, imba, Вы писали:

I>Поиском наткнулся на один пост, где в базовом классе определялся метод BaseClass.CloneTo<T> where T:BaseClass. Это лучший вариант?


Почему на AssignTo(BaseClass dst)?
Re[2]: Как написать преобразование из базового в производный
От: Пельмешко Россия blog
Дата: 29.07.09 11:40
Оценка:
Здравствуйте, imba, Вы писали:
I>Буду благодарен, если кто-нить по-человечески объяснит, почему...

Может потому что базовому классу не положено знать о своих производных?
Re[2]: Как написать преобразование из базового в производный
От: imba  
Дата: 29.07.09 13:00
Оценка:
L>Почему на AssignTo(BaseClass dst)?

Правильное название — это, конечно, хорошо
Принимаемый параметр базового типа — тоже верное исправление.
Но внутри-то что написать? Хотелось бы присобачить сюда вызов MemberwiseClone(), а не писать 20 строчек кода a=a;b=b;c=c...
Re[3]: Как написать преобразование из базового в производный
От: Lloyd Россия  
Дата: 29.07.09 13:03
Оценка:
Здравствуйте, imba, Вы писали:

I>Правильное название — это, конечно, хорошо

I>Принимаемый параметр базового типа — тоже верное исправление.

Я к тому, что Generic-и тут излишни.

I>Но внутри-то что написать? Хотелось бы присобачить сюда вызов MemberwiseClone(), а не писать 20 строчек кода a=a;b=b;c=c...


Reflection
Re[3]: Как написать преобразование из базового в производный
От: imba  
Дата: 29.07.09 13:04
Оценка:
П>Может потому что базовому классу не положено знать о своих производных?

Да нет, речь шла о преобразовании из базового класса в производный, которое определяется, конечно же, в производном классе.
Я представляю, почему такое запрещено... но весьма приблизительно.
Re[3]: Как написать преобразование из базового в производный
От: _FRED_ Черногория
Дата: 29.07.09 13:06
Оценка: 1 (1) +1
Здравствуйте, imba, Вы писали:

L>>Почему на AssignTo(BaseClass dst)?

I>Правильное название — это, конечно, хорошо
I>Принимаемый параметр базового типа — тоже верное исправление.
I>Но внутри-то что написать? Хотелось бы присобачить сюда вызов MemberwiseClone(), а не писать 20 строчек кода a=a;b=b;c=c...

ИМХО, если возможно, то лучше написать эти двадцать строчек. Избавишься от рефлекшена и прочего колдунства. Это самый простой способ, и потому вплоне может сойти за самый верный.

Другой путь: какой-то свой клониатор — имеет смысл воротить тогда, когда статически неизвестно содержимое объектов. ИМХО, написание всевозможных тестов и отладка-доводка такого добра — дело непростое и даже не быстрое. Поэтому, если возможет первый способ — лучше и использовать его.
Help will always be given at Hogwarts to those who ask for it.
Re[3]: Как написать преобразование из базового в производный
От: Воронков Василий Россия  
Дата: 29.07.09 13:14
Оценка:
Здравствуйте, imba, Вы писали:

I>Правильное название — это, конечно, хорошо

I>Принимаемый параметр базового типа — тоже верное исправление.
I>Но внутри-то что написать? Хотелось бы присобачить сюда вызов MemberwiseClone(), а не писать 20 строчек кода a=a;b=b;c=c...

Ну можно сделать deep copy через сериализацию.
Re[4]: Как написать преобразование из базового в производный
От: MozgC США http://nightcoder.livejournal.com
Дата: 29.07.09 13:14
Оценка: 1 (1)
Здравствуйте, _FRED_, Вы писали:

_FR>ИМХО, если возможно, то лучше написать эти двадцать строчек. Избавишься от рефлекшена и прочего колдунства. Это самый простой способ, и потому вплоне может сойти за самый верный.

_FR>Другой путь: какой-то свой клониатор — имеет смысл воротить тогда, когда статически неизвестно содержимое объектов. ИМХО, написание всевозможных тестов и отладка-доводка такого добра — дело непростое и даже не быстрое. Поэтому, если возможет первый способ — лучше и использовать его.

Только надо учесть как часто будет меняться класс. Если часто — то каждый раз придется подправлять и этот метод клонирования, что геморойно и чревато проблемами (можно забыть).
Re[4]: Как написать преобразование из базового в производный
От: Lloyd Россия  
Дата: 29.07.09 13:23
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

I>>Но внутри-то что написать? Хотелось бы присобачить сюда вызов MemberwiseClone(), а не писать 20 строчек кода a=a;b=b;c=c...


ВВ>Ну можно сделать deep copy через сериализацию.


Как можно сделать "deep copy через сериализацию" для случая когда тип целевого объекта отличается от сериализованного?
Re[5]: Как написать преобразование из базового в производный
От: Воронков Василий Россия  
Дата: 29.07.09 13:26
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>Как можно сделать "deep copy через сериализацию" для случая когда тип целевого объекта отличается от сериализованного?


http://msdn.microsoft.com/en-us/magazine/bb985954.aspx
Figure 3
Re[5]: Как написать преобразование из базового в производный
От: _FRED_ Черногория
Дата: 29.07.09 13:27
Оценка:
Здравствуйте, MozgC, Вы писали:

_FR>>ИМХО, если возможно, то лучше написать эти двадцать строчек. Избавишься от рефлекшена и прочего колдунства. Это самый простой способ, и потому вплоне может сойти за самый верный.


MC>Только надо учесть как часто будет меняться класс. Если часто — то каждый раз придется подправлять и этот метод клонирования, что геморойно и чревато проблемами (можно забыть).

Юнит-тесты — самое безопасное лекарство от забывчивости
Help will always be given at Hogwarts to those who ask for it.
Re[3]: Как написать преобразование из базового в производный
От: Воронков Василий Россия  
Дата: 29.07.09 13:27
Оценка: 1 (1)
Здравствуйте, imba, Вы писали:

I>Правильное название — это, конечно, хорошо

I>Принимаемый параметр базового типа — тоже верное исправление.
I>Но внутри-то что написать? Хотелось бы присобачить сюда вызов MemberwiseClone(), а не писать 20 строчек кода a=a;b=b;c=c...

А вообще я что-то уже запутался. Вам нужно приведение или глубокое копирование. Если первое, то можно ведь и просто сделать реинтерпретацию памяти. Типа такого:


using System;
using System.Runtime.InteropServices;

class Program
{
    [StructLayout(LayoutKind.Explicit)]
    struct Convert
    {
        [FieldOffset(0)]
        public Base BaseClass;

        [FieldOffset(0)]
        public Derived DerivedClass;
    }


    public class Base
    {
        public string Name;
        public int Id;
    }

    public class Derived : Base
    {
        public string Title;
    }


    static unsafe void Main()
    {
        var cv = new Convert();
        cv.BaseClass = new Base { Name = "Basil", Id = 123 };

        Console.WriteLine("Id: {0}", cv.DerivedClass.Id);
        Console.WriteLine("Name: {0}", cv.DerivedClass.Name);
        Console.WriteLine("Title: {0}", cv.DerivedClass.Title);
    }    
}
Re[6]: Как написать преобразование из базового в производный
От: MozgC США http://nightcoder.livejournal.com
Дата: 29.07.09 13:30
Оценка:
Здравствуйте, _FRED_, Вы писали:

MC>>Только надо учесть как часто будет меняться класс. Если часто — то каждый раз придется подправлять и этот метод клонирования, что геморойно и чревато проблемами (можно забыть).


_FR>Юнит-тесты — самое безопасное лекарство от забывчивости


Не все их делают. Да и можно забыть подправить юнит-тест. Я даже тему создавал по этой проблеме, что мол иногда забываю править юнит-тесты Но тут для себя надо просто выработать жесткую привычку — сначала подправить тест, а потом уже дальше менять код.
Re[6]: Как написать преобразование из базового в производный
От: Lloyd Россия  
Дата: 29.07.09 13:31
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

L>>Как можно сделать "deep copy через сериализацию" для случая когда тип целевого объекта отличается от сериализованного?


ВВ>http://msdn.microsoft.com/en-us/magazine/bb985954.aspx

ВВ>Figure 3

См. выделенное
Re[7]: Как написать преобразование из базового в производный
От: _FRED_ Черногория
Дата: 29.07.09 13:36
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>>>Только надо учесть как часто будет меняться класс. Если часто — то каждый раз придется подправлять и этот метод клонирования, что геморойно и чревато проблемами (можно забыть).


_FR>>Юнит-тесты — самое безопасное лекарство от забывчивости


MC>Не все их делают. Да и можно забыть подправить юнит-тест. Я даже тему создавал по этой проблеме, что мол иногда забываю править юнит-тесты Но тут для себя надо просто выработать жесткую привычку — сначала подправить тест, а потом уже дальше менять код.


А зачем данный тест править? Тест можно написать так, что бы при добавлении новых полей не приходилось бы править тест, иначе это неправильный тест.

Если же пренебрегать хорошими практиками и рекомендациями, то начать нужно с того, что бы перестать чистить зубы и мыться. Только после этого будет иметь смысл говорить о том, что произойдёт, если не делать тесты и забывать о важном.
Help will always be given at Hogwarts to those who ask for it.
Re[7]: Как написать преобразование из базового в производный
От: Воронков Василий Россия  
Дата: 29.07.09 13:42
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>>>Как можно сделать "deep copy через сериализацию" для случая когда тип целевого объекта отличается от сериализованного?

ВВ>>http://msdn.microsoft.com/en-us/magazine/bb985954.aspx
ВВ>>Figure 3
L>См. выделенное

И что? Получил глубокую копию, потом делаешь реинтерпретацию памяти, как я показал в соседнем посте.
Re[4]: Как написать преобразование из базового в производный
От: Lloyd Россия  
Дата: 29.07.09 13:44
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

I>>Но внутри-то что написать? Хотелось бы присобачить сюда вызов MemberwiseClone(), а не писать 20 строчек кода a=a;b=b;c=c...


ВВ>А вообще я что-то уже запутался. Вам нужно приведение или глубокое копирование. Если первое, то можно ведь и просто сделать реинтерпретацию памяти. Типа такого:


Фига се! А как это работает?!! Оно память что-ли портит? Или как-то иначе?
Re[5]: Как написать преобразование из базового в производный
От: Воронков Василий Россия  
Дата: 29.07.09 13:49
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>Фига се! А как это работает?!! Оно память что-ли портит? Или как-то иначе?


Работает также как reinterpret_cast в C++ Т.е. данные одного типа в памяти интерпретируются как данные другого типа. При желании можно и попортить что-нибудь. Но в данном конкретном случае это безопасно.
Re[6]: Как написать преобразование из базового в производный
От: Lloyd Россия  
Дата: 29.07.09 13:58
Оценка: +2
Здравствуйте, Воронков Василий, Вы писали:

L>>Фига се! А как это работает?!! Оно память что-ли портит? Или как-то иначе?


ВВ>Работает также как reinterpret_cast в C++ Т.е. данные одного типа в памяти интерпретируются как данные другого типа. При желании можно и попортить что-нибудь. Но в данном конкретном случае это безопасно.


Не понимаю, как это может быть безопасно?
Поля BaseClass и DerivedClass ссылаются на один участок памяти. Этот участок памяти выделен вызовом "new Base", значит размер выделенного участка не больше чем размер класса Base. Значит при попытке записать в поле Title мы пишем в область за выделенным участком, т.е портим память.

У меня где-то ошибка в рассуждениях? Где?
Re[6]: Как написать преобразование из базового в производный
От: Silver_s Ниоткуда  
Дата: 29.07.09 16:58
Оценка:
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Здравствуйте, Lloyd, Вы писали:
L>>Фига се! А как это работает?!! Оно память что-ли портит? Или как-то иначе?
ВВ>Работает также как reinterpret_cast в C++ Т.е. данные одного типа в памяти интерпретируются как данные другого типа. При желании можно и попортить что-нибудь. Но в данном конкретном случае это безопасно.

На чтение может и безопасно (служебные данные за пределами класса читать).
А на запись, если клас чуть побольше (еще 2 int добавлено в Derived) то все падает:

public class Derived : Base
{
    public string Title;
    public int  id1,id2; 
}
public class Base
{
    public string Name;
    public int Id;
}

[StructLayout(LayoutKind.Explicit)]
struct Convert
{
    [FieldOffset(0)]
    public Base BaseClass;
    [FieldOffset(0)]
    public Derived DerivedClass;        
}


Тогда студия падает:

    var cv = new Convert();
    cv.BaseClass = new Base{ Name = "Basil", Id = 123 };
    var victim = new Base { Name = "Victim", Id = 13 };
    cv.DerivedClass.id1 = 1;
    cv.DerivedClass.id2 = 1;

         //При отладке 'System.ExecutionEngineException', или студия падает,виснет, иногда даже не доходя до этой точки. 
         //Но несколько раз прокатывало нормально.
    var t = victim.GetType();
Re[8]: Как написать преобразование из базового в производный
От: MozgC США http://nightcoder.livejournal.com
Дата: 29.07.09 22:12
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>А зачем данный тест править? Тест можно написать так, что бы при добавлении новых полей не приходилось бы править тест, иначе это неправильный тест.


Ты имеешь в виду reflection использовать в тесте?
Re[9]: Как написать преобразование из базового в производный
От: _FRED_ Черногория
Дата: 30.07.09 05:58
Оценка:
Здравствуйте, MozgC, Вы писали:

_FR>>А зачем данный тест править? Тест можно написать так, что бы при добавлении новых полей не приходилось бы править тест, иначе это неправильный тест.


MC>Ты имеешь в виду reflection использовать в тесте?


Да всё что угодно: можно отражение, а можно кодогенерацию кода теста.
Help will always be given at Hogwarts to those who ask for it.
Re[10]: Как написать преобразование из базового в производны
От: MozgC США http://nightcoder.livejournal.com
Дата: 30.07.09 12:29
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>>>А зачем данный тест править? Тест можно написать так, что бы при добавлении новых полей не приходилось бы править тест, иначе это неправильный тест.

MC>>Ты имеешь в виду reflection использовать в тесте?
_FR>Да всё что угодно: можно отражение, а можно кодогенерацию кода теста.

Тогда не проще ли в методе клонирования использовать reflection если все равно с ним тест еще писать?
Re[11]: Как написать преобразование из базового в производны
От: _FRED_ Черногория
Дата: 30.07.09 15:17
Оценка:
Здравствуйте, MozgC, Вы писали:

_FR>>>>А зачем данный тест править? Тест можно написать так, что бы при добавлении новых полей не приходилось бы править тест, иначе это неправильный тест.

MC>>>Ты имеешь в виду reflection использовать в тесте?
_FR>>Да всё что угодно: можно отражение, а можно кодогенерацию кода теста.

MC>Тогда не проще ли в методе клонирования использовать reflection если все равно с ним тест еще писать?


Я вижу большую разницу в использовании рефлекшена при написании теста и при использовании рефлекшена в рабочем коде.
Help will always be given at Hogwarts to those who ask for it.
Re[12]: Как написать преобразование из базового в производны
От: MozgC США http://nightcoder.livejournal.com
Дата: 30.07.09 15:22
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>>>>>А зачем данный тест править? Тест можно написать так, что бы при добавлении новых полей не приходилось бы править тест, иначе это неправильный тест.

MC>>>>Ты имеешь в виду reflection использовать в тесте?
_FR>>>Да всё что угодно: можно отражение, а можно кодогенерацию кода теста.
MC>>Тогда не проще ли в методе клонирования использовать reflection если все равно с ним тест еще писать?
_FR>Я вижу большую разницу в использовании рефлекшена при написании теста и при использовании рефлекшена в рабочем коде.

Ага, в одном случае придется при изменении класса изменять и метод клонирования, а в другом случае — не нужно.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.