Invoke or just call a function as commonly we do ?

Hi all

What is the difference between:

function Start()
{
  Invoke(OpenDoor, 1);
}

function OpenDoor ()
{
  Debug.Log("Make something");
}

and this:

function Start ()
{
  OpenDoor();
}

function OpenDoor ()
{
 Debug.Log("Make something");
}

Maybe the second one keeps on memory and the first one destroyes itself ?..
(My question is a performance thing)…

Thank you.

void Invoke(string methodName, float time);
Description

Invokes the method methodName in time seconds.

simply calling it calls it now.

Other than the timer and small stuff, there should be no difference in processor usage.

Well, there is the overhead of invoking a method by reflection, and by name. Frankly, Invoke should not take a string, but a delegate.

Agreed, I wrote my own invoke system that does take a delegate instead.

You should share that. :stuck_out_tongue:

I can, but it’s quite a bit of code, because it hooks into my coroutine system I wrote as well (the coroutine system allows for custom yield statements and canceling of the coroutine).

All the Invoke system does is operate a predefined coroutine that waits a certain amount of time. And it tracks the coroutine so that if you pass in the delegate to a ‘CancelInvoke’ method it cancels that custom coroutine.

Before I wrote my custom coroutine system that wraps around the existing coroutine, I used the Invoke system to do it. So it still had to call by string internally, and it served to just allow passing in a delegate (it was nice for anonymous methods). I did it by merely having a private method with a weird name, stacking the delegates in a list, and calling them as that Invoke came back. I could cancel it by removing it from the list. I prefer this newer coroutine model.

So get ready to scroll.

RadicalCoroutine:

using UnityEngine;
using System.Collections.Generic;
using System.Linq;

namespace com.spacepuppy
{
    public class RadicalCoroutine : IRadicalYieldInstruction, System.Collections.IEnumerator
    {

        #region Fields

        private Coroutine _coroutine;

        private System.Collections.IEnumerator _routine;
        private object _current;
        private DerivativeOperation _derivative;

        private bool _cancelled = false;

        #endregion

        #region CONSTRUCTOR

        private RadicalCoroutine(System.Collections.IEnumerator routine)
        {
            _routine = routine;
        }

        private void SetOwner(Coroutine co)
        {
            _coroutine = co;
        }

        #endregion

        #region Properties

        /// <summary>
        /// A refernence to the routine that is operating this RadicalCoroutine. 
        /// This can be used for yielding this RadicalCoroutine in the midst of 
        /// a standard coroutine.
        /// </summary>
        public Coroutine Coroutine { get { return _coroutine; } }

        public bool Cancelled { get { return _cancelled; } }

        #endregion

        #region Methods

        public void Cancel()
        {
            _cancelled = true;
        }

        public void Reset()
        {
            _current = null;
            _derivative = null;
            _cancelled = false;
            _routine.Reset();
        }

        private bool MoveNext()
        {
            _current = null;

            if (_cancelled)
            {
                _derivative = null;
                return false;
            }

            int derivativeResult = -1;

            derivativeResult = this.OperateDerivative();
            if (derivativeResult >= 0)
            {
                return (derivativeResult > 0);
            }

            while (_routine.MoveNext())
            {
                var obj = _routine.Current;

                if (obj is IRadicalYieldInstruction)
                {
                    _derivative = new DerivativeOperation(obj as IRadicalYieldInstruction);
                    derivativeResult = this.OperateDerivative();
                    if (derivativeResult >= 0)
                    {
                        return (derivativeResult > 0);
                    }
                }
                else if (obj is System.Collections.IEnumerable)
                {
                    _derivative = new DerivativeOperation(new RadicalCoroutine((obj as System.Collections.IEnumerable).GetEnumerator()));
                    derivativeResult = this.OperateDerivative();
                    if (derivativeResult >= 0)
                    {
                        return (derivativeResult > 0);
                    }
                }
                else if (obj is System.Collections.IEnumerator)
                {
                    _derivative = new DerivativeOperation(new RadicalCoroutine(obj as System.Collections.IEnumerator));
                    derivativeResult = this.OperateDerivative();
                    if (derivativeResult >= 0)
                    {
                        return (derivativeResult > 0);
                    }
                }
                else
                {
                    _current = obj;
                    return true;
                }
            }

            _current = null;
            _derivative = null;
            return false;
        }

        /// <summary>
        /// 1 - continue blocking
        /// 0 - stop blocking
        /// -1 - loop past
        /// </summary>
        /// <returns></returns>
        private int OperateDerivative()
        {
            if (_derivative == null) return -1;

            if (_derivative.ContinueBlocking(this))
            {
                if (_cancelled)
                {
                    _current = null;
                    return 0;
                }
                _current = _derivative.CurrentYieldObject;
                return 1;
            }
            else
            {
                _derivative = null;
                if (_cancelled)
                {
                    _current = null;
                    return 0;
                }
                _current = null;
                return -1;
            }
        }

        #endregion

        #region IRadicalYieldInstruction Interface

        object IRadicalYieldInstruction.CurrentYieldObject
        {
            get { return _current; }
        }

        bool IRadicalYieldInstruction.ContinueBlocking(RadicalCoroutine routine)
        {
            return this.MoveNext();
        }

        #endregion

        #region IEnumerator Interface

        object System.Collections.IEnumerator.Current
        {
            get { return _current; }
        }

        bool System.Collections.IEnumerator.MoveNext()
        {
            return this.MoveNext();
        }

        void System.Collections.IEnumerator.Reset()
        {
            this.Reset();
        }

        #endregion

        #region Factory Methods

        public static RadicalCoroutine StartCoroutine(MonoBehaviour behaviour, System.Collections.IEnumerator routine)
        {
            if (behaviour == null) throw new System.ArgumentNullException("behaviour");
            if (routine == null) throw new System.ArgumentNullException("routine");

            var co = new RadicalCoroutine(routine);
            co.SetOwner(behaviour.StartCoroutine(co));
            return co;
        }

        #endregion

        #region Special Types

        private class DerivativeOperation : IRadicalYieldInstruction
        {
            private IRadicalYieldInstruction _instruction;
            private DerivativeOperation _derivative;

            public DerivativeOperation(IRadicalYieldInstruction instruction)
            {
                if (instruction == null) throw new System.ArgumentNullException("instruction");
                _instruction = instruction;
            }

            public object CurrentYieldObject
            {
                get { return (_derivative != null) ? _derivative.CurrentYieldObject : _instruction.CurrentYieldObject; }
            }

            public bool ContinueBlocking(RadicalCoroutine routine)
            {
                if (_derivative != null)
                {
                    if (_derivative.ContinueBlocking(routine))
                    {
                        return true;
                    }
                    else
                    {
                        _derivative = null;
                    }
                }

                while (_instruction.ContinueBlocking(routine))
                {
                    if (_instruction.CurrentYieldObject is IRadicalYieldInstruction)
                    {
                        _derivative = new DerivativeOperation(_instruction.CurrentYieldObject as IRadicalYieldInstruction);
                        if (!_derivative.ContinueBlocking(routine))
                        {
                            _derivative = null;
                        }
                        else
                        {
                            return true;
                        }
                    }
                    else if (_instruction.CurrentYieldObject is System.Collections.IEnumerable)
                    {
                        _derivative = new DerivativeOperation(new RadicalCoroutine((_instruction.CurrentYieldObject as System.Collections.IEnumerable).GetEnumerator()));
                        if (!_derivative.ContinueBlocking(routine))
                        {
                            _derivative = null;
                        }
                        else
                        {
                            return true;
                        }
                    }
                    else if (_instruction.CurrentYieldObject is System.Collections.IEnumerator)
                    {
                        _derivative = new DerivativeOperation(new RadicalCoroutine(_instruction.CurrentYieldObject as System.Collections.IEnumerator));
                        if (!_derivative.ContinueBlocking(routine))
                        {
                            _derivative = null;
                        }
                        else
                        {
                            return true;
                        }
                    }
                    else
                    {
                        return true;
                    }
                }

                return false;
            }
        }

        #endregion

    }

}

IRadicalYieldInstruction (implement this to make a custom yield statement):

using UnityEngine;

namespace com.spacepuppy
{
    public interface IRadicalYieldInstruction
    {
        object CurrentYieldObject { get; }

        bool ContinueBlocking(RadicalCoroutine routine);
    }
}

SPComponent (where Invoke is implemented, all my component inherit from this):

using UnityEngine;
using System.Collections.Generic;

namespace com.spacepuppy
{

    /// <summary>
    /// Base contract for any interface contract that should be considered a Component
    /// </summary>
    public interface IComponent
    {
        Component component { get; }
        GameObject gameObject { get; }
        Transform transform { get; }
    }

    public abstract class SPComponent : MonoBehaviour, IComponent
    {

        #region Fields

        private List<InvokeInfo> _invokeList;

        #endregion

        #region CONSTRUCTOR

        protected virtual void Awake()
        {
            if (com.spacepuppy.Utils.Assertions.AssertRequireLikeComponentAttrib(this))
            {
                Object.Destroy(this);
            }
        }

        protected virtual void OnDestroy()
        {
            if (_invokeList != null)
            {
                foreach (var info in _invokeList)
                {
                    info.Cancel();
                }
                _invokeList = null;
            }
        }

        protected virtual void OnEnable()
        {
            this.SendMessage(SPConstants.MSG_ONSPCOMPONENTENABLED, this, SendMessageOptions.DontRequireReceiver);
        }

        protected virtual void OnDisable()
        {
            this.SendMessage(SPConstants.MSG_ONSPCOMPONENTDISABLED, this, SendMessageOptions.DontRequireReceiver);
        }

        #endregion

        #region Invoke

        public void Invoke(System.Delegate method, float time, params object[] args)
        {
            if (method == null) throw new System.ArgumentNullException("method");
            if (time <= 0f)
            {
                method.DynamicInvoke(args);
                return;
            }

            if (_invokeList == null)
            {
                _invokeList = new List<InvokeInfo>();
            }

            var info = new InvokeInfo(method, time, args);
            var r = RadicalCoroutine.StartCoroutine(this, InvokeCoroutine(info));
            info.Radical = r;
            _invokeList.Add(info);
        }

        private System.Collections.IEnumerator InvokeCoroutine(InvokeInfo info)
        {
            yield return new WaitForSeconds(info.WaitTime);
            info.Invoke();
            if(_invokeList != null) _invokeList.Remove(info);
        }

        public new void CancelInvoke()
        {
            base.CancelInvoke();
            if (_invokeList != null)
            {
                foreach (var info in _invokeList)
                {
                    info.Cancel();
                }
                _invokeList = null;
            }
        }

        public void CancelInvoke(System.Delegate method)
        {
            if (_invokeList == null) return;

            foreach (var info in _invokeList.ToArray())
            {
                if (info.Method == method)
                {
                    info.Cancel();
                    _invokeList.Remove(info);
                }
            }
        }

        private class InvokeInfo
        {
            public float WaitTime;
            public System.Delegate Method;
            public object[] Args;
            public RadicalCoroutine Radical;

            public InvokeInfo(System.Delegate m, float t, object[] a)
            {
                WaitTime = t;
                Method = m;
                Args = a;
                Radical = null;
            }

            public void Invoke()
            {
                if (Method != null) Method.DynamicInvoke(Args);
            }

            public void Cancel()
            {
                if(Radical != null) Radical.Cancel();
                Method = null;
                Args = null;
            }
        }

        #endregion

        #region Coroutine

        public Coroutine StartCoroutine(System.Collections.IEnumerable enumerable)
        {
            return this.StartCoroutine(enumerable.GetEnumerator());
        }

        public Coroutine StartCoroutine(System.Delegate method, params object[] args)
        {
            if (method == null) throw new System.ArgumentNullException("method");

            System.Collections.IEnumerator e;
            if (com.spacepuppy.Utils.ObjUtil.IsType(method.Method.ReturnType, typeof(System.Collections.IEnumerable)))
            {
                e = (method.DynamicInvoke(args) as System.Collections.IEnumerable).GetEnumerator();
            }
            else if (com.spacepuppy.Utils.ObjUtil.IsType(method.Method.ReturnType, typeof(System.Collections.IEnumerator)))
            {
                e = (method.DynamicInvoke(args) as System.Collections.IEnumerator);
            }
            else
            {
                throw new System.ArgumentException("Delegate must have a return type of IEnumerable or IEnumerator.", "method");
            }

            return this.StartCoroutine(e);
        }



        public RadicalCoroutine StartRadicalCoroutine(System.Collections.IEnumerator e)
        {
            return RadicalCoroutine.StartCoroutine(this, e);
        }

        public RadicalCoroutine StartRadicalCoroutine(System.Collections.IEnumerable e)
        {
            return RadicalCoroutine.StartCoroutine(this, e.GetEnumerator());
        }

        public RadicalCoroutine StartRadicalCoroutine(System.Delegate method, params object[] args)
        {
            if (method == null) throw new System.ArgumentNullException("method");

            System.Collections.IEnumerator e;
            if (com.spacepuppy.Utils.ObjUtil.IsType(method.Method.ReturnType, typeof(System.Collections.IEnumerable)))
            {
                e = (method.DynamicInvoke(args) as System.Collections.IEnumerable).GetEnumerator();
            }
            else if (com.spacepuppy.Utils.ObjUtil.IsType(method.Method.ReturnType, typeof(System.Collections.IEnumerator)))
            {
                e = (method.DynamicInvoke(args) as System.Collections.IEnumerator);
            }
            else
            {
                throw new System.ArgumentException("Delegate must have a return type of IEnumerable or IEnumerator.", "method");
            }

            return RadicalCoroutine.StartCoroutine(this, e);
        }

        #endregion

        #region IComponent Interface

        Component IComponent.component
        {
            get { return this; }
        }

        //implemented implicitly
        /*
        GameObject IComponent.gameObject { get { return this.gameObject; } }
        Transform IComponent.transform { get { return this.transform; } }
        */

        #endregion

    }

}

I didn’t look through the code, but it probably references some other classes that I didn’t link here. Probably some utility classes, or custom collections. It’s all part of my SP (space puppy) framework that I’ve been developing for my personal use with unity.

Also, I’ve considered breaking the StartCoroutine methods out as extension methods so you don’t necessarily have to inherit SPComponent for them to work.

Invoke though, since it stores a reference to the list of invoke calls, needs to be here. Otherewise I’d have to write a manager for it that tracked all the components and when they died and what not. I wasn’t a big fan of that, and went this way instead.

Lastly, I may change to use some generics as well. Haven’t really considered how though. But it’d be nice to get compile time checks on the calls.