views:

227

answers:

4

Hi,

I am facing a class resolution issue while trying to make my architecture flexible. To make it simple, consider the following example:

I have four tiers: UI, BL, Common and DAL

I have a base class in my BL layer as defined below:

public class User
    {
        private UserDTO _d;
        public User()
        {
            _d = new UserDTO();
        }
        public User(UserDTO d)
        {
            _d = new UserDTO(d);
        }
        public UserDTO D
        {
            get { return _d; }
            set { _d = value; }
        }

        //static method (I cannot make it non-static due to some reasons)
        public static User GetUser()
        {
            User user = new User(Provider.DAL.GetUser());
            return user;            
        }
    }

The DTO is defined as:

public class UserDTO
    {
        public int ID;
        public UserDTO()
        {
        }

        public UserDTO(UserDTO source)
        {
            ID = source.ID;
        }
    }

My DAL is defined as (it returns a DTO not a business object):

 public static UserDTO GetUser()
        {
            UserDTO dto = new UserDTO();
            dto.ID = 99;
            return dto;
        }

Now, I want to "extend" my code so that I can have one more field in my User table: Name. So I create a derived DTO class as:

 public class MyUserDTO : UserDTO
    {
    public string Name;
    public MyUserDTO()
    {
    }

    public MyUserDTO(MyUserDTO source)
    {
        Name = source.Name; //new field
        base.ID = source.ID;
    }
}

Then, I create a derived User class as:

 public class MyUser : User
    {
        public MyUser()
        {
            this.D = new MyUserDTO(); 
        }
    }

And I create my own custom DAL provider with this method:

 public static UserDTO GetUser()
        {
            UserDTO dto = new MyUserDTO();
            dto.ID = 99;
            ((MyUserDTO)dto).Name = "New Provider Name";
            return dto;
        }

Now when I access this MyUserDTO object in my BL, it loses resolution:

User.GetUser(DAL.Provider.GetUser())

and in the UI, I dont get the properties in the MyUserDTO.

Is there a method which can help me get those properties in the UI layer, even after I call the static User.GetUser() method (which will in turn call my custom provider returning a MyUserDTO object)?

Thanks,

+4  A: 

You don't inherit from a class to add in new data, only inherit if your new class is going to extend the behaviour of your old class.

Give your UserDTO a Name-Value collection to hold its data and populate that. Then you won't have an issue.

Matt Ellen
+1  A: 

You're not getting the derived behaviour because the static method in the user class can't be overriden by the MyUser class.

You should remove the static method (I know you've indicated you can't), but really you should.

Try to extract the creation of your users in another object (factory, repository,...)

BennyM
A: 

From what I can see it looks like User.GetUser() will return a User object, not a MyUserDTO object, which is why you don't get those extra fields. The DAL layer needs to abide by the contract it was written against. There are a handful of ways you could go about solving this, although some are more "right" than others.

You could cast the object you get out of User.GetUser to the appropriate object which would then give you access to the casted object's fields (assuming the object can be cast to that type). I don't really like this solution from a design perspective, but it would work:

MyDTOUser myDtoUser = User.GetUser() as MyDTOUser;

Other people have posted some other examples of ways around this so I won't repeat those here.

Ryan Elkins
+1  A: 

As others have mentioned, the problem is with the static method.

I would also suggest using generics or dependency injection to clean up your parallel object hierarchy. You don't want that duplication.

Instead of having a set of almost-identical 'User' and 'MyUser' classes, that have the same hierarchy, just do something like User and plug in the UserDTO type that you want.

If you refactor and remove the object hierarchy duplication, it may make it easier to see a good solution to get around the problem with the static GetUser().

Thomas Albright