vexe / VFW

MIT License
492 stars 67 forks source link

Strongly typed Invoke etc. #10

Closed colms closed 9 years ago

colms commented 9 years ago

I added strongly typed Invoke, InvokeRepeating etc. on my game base class. I use it because I hate passing around strings as function names because I frequently rename my functions. There is no "nameof" in 3.5 (introduced in 4.0) so I use the following:

    public static void InvokeRepeating<T>(this MonoBehaviour mb, Func<T> method, float initialDelay, float frequency)
    {
        mb.InvokeRepeating(method.Method.Name, initialDelay, frequency);
    }

    // the same as above but for procedures instead of functions
    public static void InvokeRepeating(this MonoBehaviour mb, Action method, float initialDelay, float frequency)
    {
        mb.InvokeRepeating(method.Method.Name, initialDelay, frequency);
    }

    public static void Invoke<T>(this MonoBehaviour mb, Func<T> method, float secondsDelay)
    {
        mb.Invoke(method.Method.Name, secondsDelay);
    }

    // the same as above but for procedures instead of functions
    public static void Invoke(this MonoBehaviour mb, Action method, float secondsDelay)
    {
        mb.Invoke(method.Method.Name, secondsDelay);
    }

At the moment they are extension methods but they could be overloads. I was wondering if these would be of use in BetterBehaviour. I'm not sure if it's a good fit, hence the issue instead of a pull request.

Current usage:

    void Foo()
    {
        callFrequencySeconds = 2.0f;
        initialDelaySeconds = 1.2f;
        this.InvokeRepeating(Bar, initialDelaySeconds, callFrequencySeconds);
    }

    void Bar()
    {
        print("Printed after a delay and called periodically");
    }
vexe commented 9 years ago

It's a good idea. I'm not sure if it's a feature suitable to be a part of the framework since it has a not-so-obvious allocation when passing Bar.

I like delegates, but the more I worked with Unity the less usage I had for them (at least at runtime) - When you're passing 'Bar' you're basically passing a new Action(Bar), allocates memory and generates garbage. Not a lot of people might know about this, for example someone coming from a C/C++ background, they might think that in C# delegates are like functions pointers and there's no cost in saying Action a = SomeMethod; but there is. So in your case, if you want 0 allocation you'd have to declare a 'BarProc' Action, set it to Bar and use it in Foo instead of Bar.

I think this is a user-specific feature, so it's probably best to have it live in your personal extension methods library :)

As a side note: another idea instead of using string literals in Invoke is to use a static class and store all the function names that you invoke in it as constants. So when you refactor, you don't do replaces all over the place, but just in one place. (I use the same technique for tags)

colms commented 9 years ago

Very informative comment! I come from a C++ background and like you said, assumed delegates were function pointers. A static class with constant strings is a clever way to have zero runtime overhead without the refactoring hassle.

I think this issue can be closed so. Thanks for the reply.

vexe commented 9 years ago

You're welcome. Give this a read as well http://stackoverflow.com/questions/1582754/does-using-a-delegate-create-garbage