.NET: Базовый класс изменения наследования (преобразование C ++) - PullRequest
1 голос
/ 05 сентября 2010

У меня есть два класса.Базовый класс - это A. Унаследованный класс - это B. Я хотел бы скопировать базовый класс из одного объекта в базовый класс другого объекта, не затрагивая исходный класс.Однако .NET, похоже, игнорирует копирование.Разве это не возможно в .NET.Я знаю, что это возможно в C ++.Я включил код C ++, чтобы проиллюстрировать то, что я пытаюсь достичь.

Я понимаю, что в этом конкретном примере я могу напрямую присвоить значение bClass.ValueA = aClass.ValueA.Но что, если у класса А были частные члены?Это было бы невозможно.

Примеры классов

Public Class A
    Public ValueA As String

End Class

Public Class B
    Inherits A
    Public ValueB As String

End Class

Код

    Dim aClass As New A
    Dim bClass As New B

    aClass.ValueA = "AClass"

    bClass.ValueA = "BClass"
    bClass.ValueB = "BClass"

    Dim baseBClass As A
    baseBClass = CType(bClass, A)
    baseBClass = aClass

Результаты:

aClass.ValueA = "AClass"

bClass.ValueA = "BClass"

bClass.ValueB = "BClass"

baseBClass.ValueA = "AClass"

Ожидаемые результаты:

aClass.ValueA = "AClass"

bClass.ValueA = "AClass"

bClass.ValueB = "BClass"

baseBClass.ValueA = "AClass"

C ++ Объяснение Сравнение

#include <string>
#include <iostream>

using namespace std;

class A {
public:
    string ValueA;
};

class B : public A {
public:
    string ValueB;
};



int main(int argc, char *argv[]) {
    A aClass;
    B bClass;
    aClass.ValueA = "AClass";

    bClass.ValueA = "BClass";
    bClass.ValueB = "Blcass";

    cout << aClass.ValueA <<endl;
    cout << bClass.ValueA << endl;
    cout << bClass.ValueB << endl;

    A *baseBClass;
    baseBClass = (A*) &bClass;
    *baseBClass = aClass;

    cout << aClass.ValueA <<endl;
    cout << bClass.ValueA << endl;
    cout << bClass.ValueB << endl;
    cout << baseBClass->ValueA << endl;


    return 0;
}

Предполагаемые и фактические результаты:

aClass.ValueA = "AClass"

bClass.ValueA = "AClass "

bClass.ValueB =" BClass "

baseBClass-> ValueA =" AClass "

Я не думаю, что это возможно без указателей.Я пытался

Ctype(bClass, A) = aClass
Directcast(bClass, A) = aClass

Я получаю эту ошибку:

Выражение является значением и, следовательно, не может быть целью назначения.

Ответы [ 5 ]

1 голос
/ 05 сентября 2010

Если я правильно вас понимаю, то, что вы пытаетесь сделать, это вырвать часть состояния из одного экземпляра объекта и засунуть его в горло другого экземпляра. Т.е. вы хотите нарушить инкапсуляцию.

Есть способы достичь этого, которые действительно работают и которые не нарушают инкапсуляцию, но, честно говоря, я думаю, что это пахнет действительно плохим дизайном - тот, который C ++ хотел дать вам сойти с рук, но плохой дизайн тем не менее. Похоже, вы пытаетесь злоупотреблять наследованием, когда вам действительно следует использовать агрегацию. Вы говорите, что «экземпляр B - это A», когда это на самом деле не подходит. Вместо этого это должно быть «экземпляр B имеет A». Или выразить это в коде:

Public Class A
    Public ValueA As String
End Class

Public Class B
    Public A As A
    Public ValueB As String
End Class

Обратите внимание, что B больше не спускается с A; вместо этого он имеет ссылку на экземпляр A. Когда вы создаете B, вам понадобится какой-то способ дать ему экземпляр A, чтобы вы могли инициализировать это поле - возможно, конструктор B мог бы создать A и назначить ссылку в поле, или, возможно, вы передаете экземпляр A в конструктор B. Позже, если вы решите, что он ссылается на неправильный экземпляр A, вы можете изменить его так, чтобы он ссылался на другой экземпляр.

1 голос
/ 05 сентября 2010
Dim aClass As New A
Dim bClass As New B

aClass.ValueA = "AClass"

bClass.ValueA = "BClass"
bClass.ValueB = "BClass"

Хорошо, теперь у вас есть два экземпляра, выделенных в куче, и две переменные, которые на них ссылаются.Примерно так:

Variable       Instances on the heap
--------       ---------------------

aClass ------> Instance of class A

bClass ------> Instance of class B

(Кстати, ваше именование сбивает с толку. AClass и bClass вовсе не являются классами; это переменные, которые ссылаются на instance .)

Затем вы делаете это:

Dim baseBClass As A
baseBClass = CType(bClass, A)

Итак, теперь у вас есть три переменные, но те же два экземпляра, что и раньше.Две переменные (bClass и baseBClass) обе ссылаются на один и тот же экземпляр:

Variable          Instances on the heap
--------          ---------------------

aClass ---------> Instance of class A

baseBClass -\
             >--> Instance of class B
bClass -----/

Переменная baseBClass имеет тип, отличный от переменной bClass, но обе они ссылаются на один и тот же экземпляр.

Теперь вы делаете это:

baseBClass = aClass

, который заменяет ссылку в переменной baseBClass на другую ссылку, в частности, ссылку на объект, помеченный как «экземпляр класса A» выше:

Variable          Instances on the heap
--------          ---------------------

aClass -----\
             >--> Instance of class A
baseBClass -/

bClass ---------> Instance of class B

Вы просто назначаете ссылки вокруг.На самом деле вы никогда не копируете какие-либо данные.

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

0 голосов
/ 05 сентября 2010

Одной из альтернатив является наличие класса C #, который выполняет манипуляции с указателями и добавляет метод расширения к классу B.Это было бы очень похоже на решение C ++.Это кажется лучшим решением, так как оно будет почти идентично реализации C ++.

Вместо этого я использовал отражение.Это только мелкая копия, но в данном случае это не имеет значения.Конструктор копирования по умолчанию в C ++ - это всего лишь мелкий клон.С некоторыми украшениями вы можете проверить, существует ли IClonable, и попытаться клонировать его, в противном случае создать новый объект.Я обновил это, чтобы включить частных членов.


Imports System.Runtime.InteropServices
Imports System.Reflection

Public Class A
    Private ValueA As String
    Public Sub New(ByVal ValueA As String)
        Me.ValueA = ValueA
    End Sub
    Public Overrides Function ToString() As String
        Return String.Format("{0}:{1}={2}", _
        Me.GetType.Name, "ValueA", ValueA)
    End Function
End Class

Public Class B
    Inherits A
    Private ValueB As String
    Public Sub New(ByVal ValueA As String, ByVal ValueB As String)
        MyBase.New(ValueA)
        Me.ValueB = ValueB
    End Sub
    Public Overrides Function ToString() As String
        Return String.Format("{0}:{1}={2},{3}", _
        Me.GetType.Name, "ValueB", ValueB, MyBase.ToString)
    End Function
End Class

Module Inheritence

    Sub Main()
        Dim aClass As New A("AClass")
        Dim bClass As New B("BClass", "BClass")

        Console.WriteLine(aClass)
        Console.WriteLine(bClass)

        For Each item As FieldInfo In aClass.GetType.GetFields( _
                                             BindingFlags.Public _
                                             Or BindingFlags.Instance _
                                             Or BindingFlags.NonPublic _
                                             Or BindingFlags.Static)
            item.SetValue(bClass, item.GetValue(aClass))
        Next
        Console.WriteLine(aClass)
        Console.WriteLine(bClass)
        Console.ReadKey()
    End Sub

End Module

Клон базового класса

Это сайт, на котором я основал свое решение.Это неглубокий клон, но его легко и быстро реализовать http://www.codeproject.com/KB/cs/cloneimpl_class.aspx

Это решение лучше, поскольку оно пытается выполнить глубокое клонирование объектов, поддерживающих IClonable, иначе оно просто устанавливает новый экземпляр.http://whizzodev.blogspot.com/2008/03/object-cloning-using-il-in-c.html

Процедуры клонирования:

Это интересный сайт, который объясняет различные методы клонирования.http://developerscon.blogspot.com/2008/06/c-object-clone-wars.html

Еще один интересный ресурс. Глубокое клонирование объектов

Обсуждение глубокого клонирования Создание Deep Copy в C #

0 голосов
/ 05 сентября 2010

Когда вы назначаете baseBClass = aClass, вы назначаете указатель, который ссылается на aClass.

Это заменит указатель на bClass, который хранился здесь: baseBClass = CType (bClass, A).

Я думаю, вам может понадобиться использовать конструктор копирования в A для достижения желаемого эффекта.

0 голосов
/ 05 сентября 2010

Я просто пронумеровал строки вашего кода для удобства:

1 Dim aClass As New A
2 Dim bClass As New B

3 aClass.ValueA = "AClass"

4 bClass.ValueA = "BClass"
5 bClass.ValueB = "BClass"

6 Dim baseBClass As A
7 baseBClass = CType(bClass, A)
8 baseBClass = aClass

Вам присваивается bClass.ValueA значение "BClass" в строке 4, так что именно это делает вывод таким, какой он есть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...