11

I'm coding with a state pattern for an embedded device. I have a base/abstract class called State and then each discrete(concrete) state class implements the abstract State Class.

In the State Class I have several Abstract Methods. If I don't implement the abstract methods in the discrete(concrete) class, Visual Studio will give an error something like this:

...Error 1 'myConcreteState' does not implement inherited abstract member 'myAbstractState'

Now: I'm trying to create a String property for each State called StateName. Whenever I create a new concrete class, I need to define StateName. I want VS to throw an error if I don't use it. Is there a simple way to do this?

I've tried this in the abstract/base class:

public abstract string StateName { get; set; }

But I don't need to implement the Get and Set methods in each State.

Revised Question: In an ideal situation, each State Class would be required to have StateName defines and be inherited from the abstract base class.

StateName = "MyState1"; //or whatever the state's name is

If that statement is missing then Visual Studio will generate an error as described above. Is this possible and if so, how?

7
  • 2
    I don't understand the question. Commented Jun 6, 2015 at 17:35
  • I guess the "correct" way to do this is to have a protected constructor on the base class which requires the state name as a parameter. Commented Jun 6, 2015 at 17:45
  • @RomanReiner I thought about doing that as well..but it seems redundant because each time change/call a state, I would have to type in the name.
    – GisMofx
    Commented Jun 6, 2015 at 20:47
  • @BenAaronson I've clarified my question near the bottom.
    – GisMofx
    Commented Jun 6, 2015 at 20:54
  • Is the state name constant per type or constant per instance? Commented Jun 7, 2015 at 0:09

4 Answers 4

19

I guess the "correct" way to do this is to have a protected constructor on the base class which requires the state name as a parameter.

public abstract class State
{
    private readonly string _name;

    protected State(string name)
    {
        if(String.IsNullOrEmpty(name))
            throw new ArgumentException("Must not be empty", "name");

        _name = name;
    }

    public string Name { get { return _name; } }
}

The concrete states then provide a public constructor which implicitly calls the base class constructor with the appropriate name.

public abstract class SomeState : State
{
    public SomeState() : base("The name of this state")
    {
        // ...
    }
}

Since the base class does not expose any other constructors (neither protected nor public) each inheriting class needs to go through this single constructor and thus needs to define a name.

Note that you don't need to provide the name when you instantiate a concrete state because its constructor takes care of that:

var someState = new SomeState(); // No need to define the name here
var name = someState.Name; // returns "The name of this state"
1
  • 1
    Thanks! In reality, my base class constructor now takes an additional argument; so I have two inputs. As soon as I set this up, I get errors that I need an additional argument in the state class constructors ...:base(arg1, arg2)! This is a solution that I was looking for. This really helps with keeping my State coding more consistent.
    – GisMofx
    Commented Jun 9, 2015 at 14:07
5

As of C# 6 (I believe - C# : The New and Improved C# 6.0) you are able to create getter only properties. So you could declare your base class like so -

public abstract class State
{
    public abstract string name { get; }

    // Your other functions....
}

And then in your sub-class you can implement State like so -

public class SomeState : State
{
    public override string name { get { return "State_1"; } }
}

Or even neater using the lambda operator -

public class SomeState : State
{
    public override string name => "State_1";
}

Both would always return "State_1" and be immutable.

1
  • 1
    this can be written public override string name { get; } = "State_1"; which then doesn't need to reevaluate the value each time. Commented Nov 13, 2018 at 19:43
2

Your requirements are a contradiction:

I'm trying to create a String property for each State called StateName.

vs.

But I don't need to implement all of that in each State.

There's no language feature that allows you to force the existence of a member in only a few sub classes. After all, the point of using a super class is to rely on the fact that all subclasses will have all the members of the super class (and possibly more). If you want to create classes that act as a State but dont have a name, then by definition, they should (/can) not be subclasses of State.

You either have to change your requirements or use something other than simple inheritance.

A possible solution with the code as it is could be to make the method in State non abstract and return an empty string.

3
  • I think you took that second statement out of context, but I will clarify. I don't need the Get/Set methods, I simply want StateName = "MyState1" in each State. If I do not have that statement in the state class, then ideally Visual Studio will generate an error.
    – GisMofx
    Commented Jun 6, 2015 at 20:50
  • 3
    @GisMofx If you want to force the state name in each subclass, make the get abstract but don't require a state. Then each subclass will have to provide return "MyState1" as their implementation, and can add mutable storage for the value if they need it. But you need to clarify the requirements in the question - does every type of state require a StateName which can be read, and does any type of state require it to be mutated after creation? Commented Jun 6, 2015 at 21:05
  • @PeteKirkham each state requires a name, it should not be mutated after creation. The states' names are static/immutable.
    – GisMofx
    Commented Jun 9, 2015 at 13:32
1

You can't do this with an abstract class, but you can do it with an interface.

public interface IState
{
    public string Name { get; }
}

// This won't compile: 'SomeState' does not implement interface member 'IState.Name'
public class SomeState : IState
{
}

// This will compile
public class SomeState : IState
{
    public string Name => "SomeState's Name";
}

See here for more: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/interface-properties

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.