简体   繁体   中英

C#: How can I set a maximal Value of a property from a derived class? (And not in base class)

CannibalGhost : Ghost (CannibalGhost dervies from Ghost)

CannibalGhost can eat any sort of Ghosts and get their Height added to his Height. However Ghosts should be able to be as big as they want, while CannibalGhosts should only be at a maximum Height of 50. It can't surpass under any circumstances. Not via. set-accessor and not via constructor.

I have tried so far:

  • override Constructor :

    Can't override constructor

  • implementing a if( height >= 50 ) in Set-Accessor

    does not work if I create an object with a constructor in the Main-Program

  • implementing a barrier in Main-Code so height never gets over 50

    does not work if I want new objects of CannibalGhost later (and is a mess)

  • writing it so CannibalGhost does not derive from Ghost

    So I am able to write a new constructor and set-Accessor with a ceiling of 50. It worked but I want CannibalGhosts also to be a Ghost (derive from Ghost)

Summary: How can I set the property Height of CannibalGhost to max 50, but not in the base class Ghost ?

You could build Ghost in such a way that it knows that some validation is required in derived class(es) without implementing the logic itself in the base class

public class Ghost
{
    private int height;

    protected virtual bool IsValidHeight(int newHeight)
    {
        return true;
    }

    public int Height
    {
       get{ return height; }
       set
       {
           if(!IsValidHeight(value) throw new InvalidHeightException(value);
           height = value;
       }
    }
}

public class CannibalGhost 
{
    protected override bool IsValidHeight(int newHeight
    {
        return newHeight <= 50;
    }
}

perhaps instead of throwing an exception you want to limit the height you could make that virtual method

protected virtual int LimitHeight(int newHeight)
{
     return newHeight;
}

and

protected override int LimitHeight(int newHeight)
{
    return (int)Math.Min(newHeight,50);
}

then the setter would just be

set
{
    height = LimitHeight(value);  
}

This would have no effect on Ghost but would limit the derived CannibalGhost to 50.


In truth, this is not a great solution. You can't know when designing a base class all the places you might want this sort of validation down the line - and its the reason inheritance breaks down for more complex solutions than this simple example.

Does CannibalGhost really have an is-a relationship with Ghost ? Or is it actually composed of multiple Ghost instances (a has-a-collection-of relationship). In this case it's height could merely be a sum of all its composed Ghost instances with a limit of 50. No inheritance required. Perhaps all ghosts implement IGhost for shared behaviours - something to consider!

By making the Height property virtual in the base class you can have derived classes implement more specific behaviour by overriding it.

Example:

public class Ghost
{
    public virtual int Height { get; set; }
}

public class CannibalGhost : Ghost
{
    private int _height;
    public override int Height
    {
        get
        {
            return _height;
        }
        set
        {
            if (value > 50)
                throw new InvalidOperationException($"A {nameof(CannibalGhost)} cannot have a height over 50");

            _height = 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