简体   繁体   中英

C# polymorphism issue

I have a BL class named:A , DTO class named:DTO . Now assume I want to add some more properties in my DTO. So I derive a new DTO class from my existing DTO and add properties to it.Below is the code:

namespace TestConsole
{
    class test
    {
        static void Main(string[] args)
        {

            B b = new B();
            b.D.ID = 1;
            b.D.Name = "4";
            MyBLMethod(b);

        }
        static void MyBLMethod(A b)
        {
            MyDALMethod(b.D);
        }

        static void MyDALMethod(DTO dto)
        {
           int i = dto.ID;
           string name = ((MyDTO)dto).Name;//I could not do this 
            //because i will get object cast error as i can't cast from 
            //parent to child
        }

    }
    public class DTO
    {
        public int ID = 99;
        public DTO()
        {
        }

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

    public class MyDTO : DTO
    {
        public string Name = "";
        public MyDTO() { }
        public MyDTO(MyDTO source)
            : base(source)
        {
            Name = source.Name;

        }
    }
    public class A
    {
        private DTO _d;
        public A()
        {
            D = new DTO();

        }

        public DTO D
        {
            get { return _d; }
            set { _d = value; }
        }
    }

    public class B : A
    {
        private MyDTO _md;
        public B()
        {
            _md = new MyDTO();

        }

        public MyDTO D
        {
            get { return _md; }
            set { _md = value; }
        }
    }

}

From Main (you can think it as UI) i am calling MyBLMethod (present in BL repository) and passing class object to it , and from BL repository i am calling my DAL. In DAL i have written this:

static void MyDALMethod(DTO dto)
{
    int i = dto.ID;
    string name = ((MyDTO)dto).Name;//I could not do this 
       //because i will get object cast error as i can't cast from 
       //parent to child
}

Could you suggest me how could i get the newly extended property (name in the example) in my DAL.

When B inherits A, it already owns a DTO attribute. So the problem is really that you are hidding this inheritance. You don't need a new property inside B class, just set it in your class constructor.

public class B : A
    {
        public B()
        {
            this.D = new MyDTO();
        }

    }

But, in your main class you will need a explicit cast in your property, just like below, since DTO does not have a "Name" property.

static void Main(string[] args)
        {
            B b = new B();
            b.D.ID = 1;
            ((MyDTO)b.D).Name = "4";
            MyBLMethod(b);
        }

If the object is ACTUALLY of the base type, you can't just tack on the additional properties. Doesn't work that way, sorry.

What you want is to CONVERT the object (maybe). Make a constructor in your child class that can take a parent and copy all of it's stuff into itself - then you'll have the additional properties.

The reason that the cast fails, is that you are not passing a MyDTO object to the method, but a DTO object. The MyBLMethod method always sends the DTO object to the DAL even if there is a MyDTO object.

You haven't made the D property virtual. That means that when you use the D property on an A reference, you get the DTO object that the A class contains even if the actual object happens to the a B instance so that it also has a MyDTO object.

You can make the D property virtual to access the D property of the actual object instead of the one specified by the type of the reference.

Or you can cast the reference to B so that you can access it's MyDTO object instead of it's DTO object:

static void MyBLMethod(A b) {
   MyDALMethod(((B)b).D);
}

Note that the B class contains both a DTO and a MyDTO object, which might not be what you really want.

It sounds like you are losing "resolution" because you are passing through a static business logic method. I would suggest revisiting that part rather than struggling with the DAL method first.

There may be a reason you're stuck with that though, so if you are, you can consider using reflection to find the properties you need or using an "as" cast and then testing for null in your dal method. If you aren't stuck with this design, I'd refactor my way out of the static method though. Static seems so easy and unfortunately there's a lot of code 'quality' tools pushing you to make methods static which forget to remind you can't easily change static methods to virtual methods later.

Allow B to pass A a DTO object in A 's constructor. If needed, make the constructor protected . Then, have BD cast AD .

public class A
{
    private DTO _d;

    // New constructor.
    protected A(DTO d)
    {
        _d = d;
    }

    // Old constructor calls new constructor.
    public A() : this(new DTO())
    {
    }

    public DTO D
    {
        get { return _d; }
        set { _d = value; }
    }
}

public class B : A
{
    // Old B constructor calls new A constructor.
    public B() : base(new MyDTO())
    {
    }

    new public MyDTO D
    {
        // Getting D casts A.D instead of using an object exclusive to B.
        get { return (MyDTO)base.D; }
        set { base.D = value; }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM