What's the right 'T' for a Func<T> that returns itself?

Viewed 92

A function that returns a value:

public object ReturnValue() { return new object(); }
Func<object> funcReturnValue = ReturnValue;

A function that retuns a function that returns a value:

public Func<object> ReturnFunc() { return ReturnValue; }
Func<Func<object>> funcReturnFunc = ReturnFunc;

So far, so good. I'm having trouble with a function that returns itself:

public *something* ReturnSelf() { return ReturnSelf; }
Func<*something*> funcReturnSelf = ReturnSelf;

Clearly, *something* is going to be a Func<T> of some kind, but I'm not sure what. At first glance I guess it's going to be infinity recursive, since ReturnSelf returns a function that returns a function that returns a function...

Context: A state machine using functions for states. It works fine using a class variable to keep the current state:

private Action _currentState;

private void StateOne() {
    if (IsTuesday) {
        _currentState = StateTwo;
    }
}

prvivate void StateTwo() {
    if (IsRaining) {
        _currentState = StateOne;
    }
}

private void StateEngine() {
    while (true) {
        _currentState();
        // set tuesday/raining/etc.
    }
}

...but that feels too much like keeping state in a global. I'd far prefer something closer to:

private Func<*somthing*> StateOne() {
    if (IsTuesday) {
        return StateTwo;
    } else {
        return StateOne;
    }
}

prvivate Func<*something*> StateTwo() {
    if (IsRaining) {
        return StateOne;
    } else {
        return StateTwo;
    }
}

private void StateEngine() {
    Func<*something*> currentState = StateOne;
    while (true) {
        Func<*something*> nextState = currentState();
        // set tuesday/raining/etc.
        currentState = nextState;
    }
}

Any ideas? Or should I just stick with the working solution?

2 Answers

Instead of using Func<T> you could define a delegate which returns a value of that delegate type. Delegates can be used to pass function references as arguments to another function, or in this case to return a function reference from a function (docs).

Example:

class Program
{

  private delegate StateDelegate StateDelegate();

  public static void Main(string[] args)
  {
    Program program = new Program();
    StateDelegate stateHandler = program.HandleStateOne;
    
    // Execute HandleStateOne, returns HandleStateTwo
    stateHandler = stateHandler.Invoke(); 

    // Execute HandleStateTwo, returns reference to HandleStateOne    
    stateHandler = stateHandler.Invoke();
  }

  private StateDelegate HandleStateOne()
  {
    // Do something state specific...
    return HandleStateTwo;
  }

  private StateDelegate HandleStateTwo()
  {
    // Do something state specific...
    return HandleStateOne;
  }

  // Literally return reference to the function itself
  private StateDelegate ReturnSelf()
  {
    return ReturnSelf;
  }
}

You can do this with the help of an extra type:

class State
{
    private Func<State> _func; 
    
    public State(Func<State> func)
    {
        _func = func;
    }
    
    public State Invoke() => _func();
}

And then you can write:

bool IsTuesday = false;
bool IsRaining = false;
State StateOne = null;
State StateTwo = null;

StateOne = new State
(
    () =>
    {
        if (IsTuesday) {
            return StateTwo;
        } else {
            return StateOne;
        }
    }
);
    
StateTwo = new State
(
    () =>
    {
        if (IsRaining) {
            return StateOne;
        } else {
            return StateTwo;
        }
    }
);

And, of course:

void StateEngine() {
    State currentState = StateOne;
    while (true) {
        var nextState = currentState.Invoke();
        // set tuesday/raining/etc.
        currentState = nextState;
    }
}

We may do a little more, with an implicit conversion to Func<State> (and then you don't need an invoke method anymore):

public static implicit operator Func<State> (State state)
{
    return state._func;
}

Then you can write:

void StateEngine() {
    Func<State> currentState = StateOne;
    while (true) {
        Func<State> nextState = currentState();
        // set tuesday/raining/etc.
        currentState = nextState;
    }
}

So, Func<State> returns something that can be converted implicitly into Func<State>.

Code in SharpLap

Related