开发者

Strange Inheritance Issue with C# classes

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;
    }
}

now let's execute the following code

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());
}

the problem is that

  1. I expect b.ToValueObject have all properties set, but in reality only get properties from DTOb class (so I FirstName and Id properties are NULL, however I set the explicitly)

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

Any ideas why ID is not set and FirstName is not set? DTOb is inherited from DTOa and thus "Should" include all the properties from DTOa. It's working on the code level, so if I write console.WriteLine(b.Firstname) - I'll get the value correct, but when I call ToValueObject() method - it got deleted.


OKay here is working example:

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;
    }
}


DTOb is inherited from DTOa and thus "Should" include all the properties from DTOa

This is true, but you also have this:

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

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

That is, class a and b are both working with different instances of the "DTO" class. In fact, your compiler should be giving you a warning about the _DTO in b "hiding" the _DTO field in a.

What you want to do is make sure that both classes are accessing the same instance. You can't override fields, but you can override methods so something like this might be suitable:

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; }
    }

    ...
}

To be honest, I'm not quite sure what the benefit of this "DTO" object is, but the above should give you the behaviour you're after.


I see little point in duplicating the functionality of DTOa and DTOb with your a and b classes. It's generally an anti-pattern, unless you have a specific reason to intercept the values before they reach DTOa.

Anyway, you can fix your code using some generics.

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";


This is because your b class makes its own DTO object (protected DTOb _DTO = new DTOb()) and modifies this and your a class makes its own DTO object (protected DTOa _DTO = new DTOa()) and modifies this.

At no stage does your b class pass its object up to a to be modified.

Furthermore, your GetValueObject is only going to return the instance within that class.

To get what you want you need a property like:

public DTOa DTO { get; }

Which is overridden in your b class, and make sure all your set methods set through this call. You'll have to do some casting with your b one though when you use it.


You should be getting warnings about your _DTO field and ToValueObject method hiding the corresponding field/method from class a. What is happening is that the class b object has both a DTOa and a DTOb object both known as _DTO and the methods in a refer to the DTOa object and the methods in b refer to the DTOb object.

Personally I think you're going at this the wrong way. It looks like you're trying to model a user and a user with contact information. I'd suggest that there isn't really an inheritance relationship ("is a") here, but rather a "has a" relationship -- a user has contact information. If you modeled it this way you'd have UserDTO and a ContactDTO and your user object would contain both a UserDTO and a ContactDTO (or a reference to a Contact which has a ContactDTO object).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜