Issue
Init(args) only supports passing a maximum of twelve arguments to a component that derives from MonoBehaviour<T…> or implements IInitializable<T…> during its initialization.
What can you do if you have a legacy class that depends on more than twelve external objects, and you want to refactor the class to derive from MonoBehaviour<T…> and receive those arguments via Init(args)?
Solution #1: Extract Class
Having more than twelve dependencies is a strong indicator that your class probably has too many responsibilities.
Consider applying extract class refactoring on the component in order to split it into multiple smaller components that require a smaller number of Init arguments.
class Player : MonoBehaviour<IInputManager, Collider, Rigidbody, Camera, … > { … } ↓ class Player : MonoBehaviour< … > { … } class CollisionHandler : MonoBehaviour<Collider> { … } class AimHandler : MonoBehaviour<Camera, IInputManager> { … } class MoveHandler : MonoBehaviour<IInputManager, Rigidbody> { … }
Solution #2: Parameter Object
Another thing that could help is to apply parameter object refactoring to combine multiple dependencies into one object.
class Player : MonoBehaviour<Collider, Rigidbody, … > { … } ↓ class Player : MonoBehaviour<PlayerPhysics, … > { … }
Solution #3: Tuple
If you don’t have time to get fancy with refactoring at this time, as a quick workaround you can use tuple to combine as many objects as you want into a single Init argument:
public class INeedThirteenArgs : MonoBehaviour<(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m)> { private int a, b, c, d, e, f, g, h, i, j, k, l, m; protected override void Init((int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m) args) { a = args.a; b = args.b; c = args.c; d = args.d; e = args.e; f = args.f; g = args.g; h = args.h; i = args.i; j = args.j; k = args.k; l = args.l; m = args.m; } }
Then when initializing your object, instead of passing in each service separately, you just pass in the single tuple:
var args = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13); gameObject.AddComponent(out INeedThirteenArgs result, args);
To create a Initializer for the component that supports assigning each of the services contained inside the tuple separately using the Inspector, you can have it derive from InitializerBase. While the Initializer base class handles visualizing and serializing the Init arguments for you, the InitializerBase leaves it up to you to implement this manually:
class INeedThirteenArgsInitializer : InitializerBase<INeedThirteenArgs, (int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m)> { [SerializeField] Any<int> a; [SerializeField] Any<int> b; [SerializeField] Any<int> c; [SerializeField] Any<int> d; [SerializeField] Any<int> e; [SerializeField] Any<int> f; [SerializeField] Any<int> g; [SerializeField] Any<int> h; [SerializeField] Any<int> i; [SerializeField] Any<int> j; [SerializeField] Any<int> k; [SerializeField] Any<int> l; [SerializeField] Any<int> m; protected override (A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m) Argument { get => (a.GetValue(this), b.GetValue(this), c.GetValue(this), d.GetValue(this), e.GetValue(this), f.GetValue(this), g.GetValue(this), h.GetValue(this), i.GetValue(this), j.GetValue(this), k.GetValue(this), l.GetValue(this), m.GetValue(this)); set { a = value.a; b = value.b; c = value.c; d = value.d; e = value.e; f = value.f; g = value.g; h = value.h; i = value.i; j = value.j; k = value.k; l = value.l; m = value.m; } } }