Странная проблема наследования с классами C # - PullRequest
0 голосов
/ 08 июля 2010
public class DTOa
{
    public int Id { get; set;}
    public string FirstName { get; set;}
}

public class DTOb: DTOa
{
    public string Email { get; set;}
    public string Password { get; set; }
}

public class a
{
    protected DTOa _DTO = new DTOa();
    public int Id
    {
        get
        {
            return _DTO.Id;
        }
        set
        {
            _DTO.Id = value;
        }
    }

    public string FirstName
    {
        get
        {
            return _DTO.FirstName;
        }
        set
        {
            _DTO.FirstName = value;
        }
    }

    public DTOa ToValueObject()
    {
        return _DTO;
    }
}

public class b: a
{
    protected DTOb _DTO = new DTOb();

    public string Email
    {
        get
        {
            return _DTO.Email;
        }

        set
        {
            _DTO.Email = value;
        }
    }

     public string Password
    {
        get
        {
            return _DTO.Password;
        }

        set
        {
            _DTO.Password  = value;
        }
    }

    public DTOb ToValueObject()
    {
        return _DTO;
    }
}

теперь выполним следующий код

public function test() 
{       
   var a = new a();
   var b = new b();
   b.Id = 100;
   b.FirstName = "Jim";
   b.Email = "email@email.com";
   b.Password = "test";
   Console.WriteLine(b.ToValueObject().Dump());
}

проблема в том, что

  1. Я ожидаю, что b.ToValueObject имеет все установленные свойства, но в действительности получает свойства только из класса DTOb (поэтому свойства FirstName и Id равны NULL, однако я устанавливаю явно)

    dump:
    {
            Email: email@email.com,
            Password: test,
            Id: 0
    }
    

Есть идеи, почему ID не установлен, а FirstName не установлен? DTOb наследуется от DTOa и, следовательно, «Должен» включать все свойства от DTOa. Это работает на уровне кода, поэтому, если я напишу console.WriteLine(b.Firstname) - Я получу правильное значение, но когда я вызову метод ToValueObject() - оно будет удалено.


Хорошо, вот рабочий пример:

public class DTOa : IDTO
{
    public int Id { get; set; }
    public string FirstName { get; set; }
}

public class DTOb : DTOa, IDTO
{

    public string Email { get; set; }
    public string Password { get; set; }
}

public class a
{
    protected IDTO _DTO;

    public a()
    {
        _DTO = new DTOa();
    }

    public int Id
    {
        get
        {
            return (_DTO as DTOa).Id;
        }
        set
        {
            (_DTO as DTOa).Id = value;
        }
    }

    public string FirstName
    {
        get
        {
            return (_DTO as DTOa).FirstName;
        }
        set
        {
            (_DTO as DTOa).FirstName = value;
        }
    }

    public DTOa ToValueObject()
    {
        return (_DTO as DTOa);
    }

}

public class b : a
{
    public b()
    {
        _DTO = new DTOb();
    }

    public string Email
    {
        get
        {
            return (_DTO as DTOb).Email;
        }

        set
        {
            (_DTO as DTOb).Email = value;
        }
    }

    public string Password
    {
        get
        {
            return (_DTO as DTOb).Password;
        }

        set
        {
            (_DTO as DTOb).Password = value;
        }
    }

    public DTOb ToValueObject()
    {
        return _DTO as DTOb;
    }
}

Ответы [ 4 ]

6 голосов
/ 08 июля 2010

DTOb наследуется от DTOa и, следовательно, «Должен» включать все свойства из DTOa

Это верно, но у вас также есть это:

public class a
{
    protected DTOa _DTO = new DTOa();
    ...
}

public class b
{
    protected DTOb _DTO = new DTOb();
    ...
}

То есть класс a и b работают с различными экземплярами класса "DTO".Фактически, ваш компилятор должен предупреждать вас о том, что _DTO in b "скрывает" поле _DTO в a.

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

class A
{
    private DTOa _dto = new DTOa();
    protected virtual DTOa GetDTO()
    {
        return _dto;
    }

    public string FirstName
    {
        get { return GetDTO().FirstName; }
        set { GetDTO().FirstName = value; }
    }

    ...
}

class B : A
{
    private DTOb _dto = new DTOb();
    protected virtual DTOa GetDTO()
    {
        return _dto;
    }

    public string Email
    {
        get { return GetDTO().Email; }
        set { GetDTO().Email = value; }
    }

    ...
}

Если честно, я не совсем уверен, в чем преимущество этого объекта "DTO",но вышесказанное должно дать вам поведение, за которым вы следуете.

0 голосов
/ 08 июля 2010

Не вижу смысла дублировать функциональность DTOa и DTOb с вашими классами a и b. Обычно это анти-паттерн, если только у вас нет особой причины перехватывать значения до того, как они достигнут DTOa.

В любом случае, вы можете исправить свой код с помощью некоторых обобщений.

public class a<T> where T : DTOa {
    private readonly T _DTO = Activator.CreateInstance<T>();

    protected T DTO { get { return this._DTO; } }

    //properties
}

public class b<T> : a<T> where T : DTOb {
    //NB: Don't override or hide DTO.
    //properties
}


var a = new a<DTOa>();
var b = new b<DTOb>();
b.Id = 100;
b.FirstName = "Jim";
b.Email = "email@email.com";
b.Password = "test";
0 голосов
/ 08 июля 2010

Вы должны получать предупреждения о том, что ваше поле _DTO и метод ToValueObject скрывают соответствующее поле / метод от класса a. Происходит то, что у объекта класса b есть и объект DTOa, и объект DTOb, оба известные как _DTO, а методы в ссылке на объект DTOa, а методы в b ссылаются на объект DTOb.

Лично я думаю, что вы ошибаетесь. Похоже, вы пытаетесь смоделировать пользователя и пользователя с контактной информацией. Я бы предположил, что в действительности здесь нет отношения наследования («это»), а отношения «имеет» - у пользователя есть контактная информация. Если вы смоделируете это таким образом, у вас будут UserDTO и ContactDTO, а ваш пользовательский объект будет содержать как UserDTO, так и ContactDTO (или ссылку на контакт, имеющий объект ContactDTO).

0 голосов
/ 08 июля 2010

Это потому, что ваш класс b создает свой собственный объект DTO (protected DTOb _DTO = new DTOb()) и изменяет его, а ваш класс a создает свой собственный объект DTO (protected DTOa _DTO = new DTOa()) и модифицирует его.

Ни на каком этапе ваш b класс не передает свой объект до a для изменения.

Кроме того, ваш GetValueObject только собирается вернуть экземпляр в этом классе.

Чтобы получить то, что вам нужно, вам нужно свойство, подобное:

public DTOa DTO { get; }

, которое переопределяется в вашем классе b, и убедитесь, что все ваши методы set установлены через этот вызов.Вам придется делать кастинг с вашим b, хотя, когда вы его используете.

...