Class which contains an instance of the same class

144 views Asked by At

I have to create a class in C#, call it Class1. This class must contain an enum field, called Flag. Flag has 4 possible values, say A,B,C,D. An instance of Class1 can contain another instance of Class1 where the state of Flag is different from A.

My question is: how to formulate the condition that the state of Flag in the sub-instance must be different from A?

3

There are 3 answers

1
Alioza On BEST ANSWER

Mark your Class1 "subinstance" as private and make it accessible only through a property. In the property setter, check that the value which is set has the flag different from the one of the parent. Be careful, if the parent Class1 flag must always be different from the child, then you also have to add a check when setting the parent flag.

0
Tim Schmelter On

You could make the setter private and check it in the constructor, you also have to provide a private constructor for the inner instance. So basically an immutable class:

public enum Flag
{
    A, B, C, D
}

public class Class1
{
    private Class1 _Class1Inner;
    public Class1 Class1Inner
    {
        get { return _Class1Inner; }
        private set { _Class1Inner = value; }
    }

    private Flag _Flag;
    public Flag Flag
    {
        get { return _Flag; }
        private set { _Flag = value; }
    }

    // used only to create the inner instance
    private Class1(Flag innerFlag)
    {
        this.Flag = innerFlag;
        _Class1Inner = null; // or whatever 
    }

    public Class1(Flag flag, Flag innerFlag)
    {
        if (innerFlag == Flag.A)
            throw new ArgumentException("innerFlag must not be Flag.A!", "innerFlag");
        this.Flag = flag;
        this.Class1Inner= new Class1(innerFlag);
    }
}

If you want this class to be mutable, so that you can change the Flag after creation, you have to remember whether it is an inner instance or not.

Therefore you need another field which you can set from the constructor:

public class Class1
{
    private bool _isInnerInstance = false;

    private Class1 _Class1Inner;
    public Class1 Class1Inner
    {
        get { return _Class1Inner; }
        private set { _Class1Inner= value; }
    }

    private Flag _Flag;
    public Flag Flag
    {
        get { return _Flag; }
        set
        {
            if (_isInnerInstance && value == Flag.A)
                throw new ArgumentException("innerFlag must not be Flag.A!", "innerFlag");
            _Flag = value;
        }
    }

    private Class1(Flag innerFlag)
    {
        this.Flag = innerFlag;
        _isInnerInstance = true;
        _Class1Inner = null; // or whatever
    }

    public Class1(Flag flag, Flag innerFlag)
    {
        if (innerFlag == Flag.A)
            throw new ArgumentException("innerFlag must not be Flag.A!", "innerFlag");
        this.Flag = flag;
        _Class1Inner = new Class1(innerFlag);
    }
}

Now following is not allowed:

Class1 cls1 = new Class1(Flag.A, Flag.B);
cls1.Class1Inner.Flag = Flag.A; // throws an ArgumentException at runtime
0
musefan On

Started as a comment, but a bit too detailed so moved to answer...

On first though then, I would say that Class1 needs a way of knowing it is a 'sub-instance', for example you could force a constructor that defines this:

private IsSub { get; set; }
public Class1(bool isSub)
{
    IsSub = isSub;
}

which sets a property in the class. This property can be used to check if the Flag can have A or not. But you will need a way to validate when the flag is set. For that you could add a validation method that throws an error to the property setter:

private Flag myFlag;
public Flag MyFlag 
{
    get { return myFlag; }
    set { ValidateFlag(value); myFlag = value; }
} 

void ValidateFlag(Flag flag)
{
    if(IsSub && flag == Flag.A)
        throw new Exception("Invalid flag");
}

Finally, you need to decide when to set the sub-instance. If you only want to allow one level of subinstance (so child class won't have their own child instances) then you can do it in the default constructor like so:

public Class1 ChildClass { get; set; }
public Class1()
{
    ChildClass = new Class1(true);
}

(You also will want to think about how the default values for the flag properties are going to be set, but that is your logic to decide on.)


Here is example usage:

Class1 myClass = new Class1();
myClass.MyFlag = Flag.A; // This is fine.
myClass.SubClass.MyFlag = Flag.A; // This will throw an exception.