Method signatures are not extensible – and will not be.
Extensible parameters would be intrusive – in so many ways:
Here are some alternatives.
The request for adding a new parameter to a method as an extension is surfacing quite frequently. A method's signature is the contract between caller and method. When new parameters are added, then callers can provide additional data that the method can act on. In isolation; a request for an extra parameter makes no sense. An extra parameter will not help anyone unless someone is passing it in, and someone is acting on it.
In the land of extensibility there are restrictions:
- You cannot change the places a given method is called, that would require overlayering. But you can call the method from your own code (with control over the parameters).
- You cannot change the implementation of the method, that would require overlayering. But often you can add logic pre/post or wrap using Chain-of-command.
With these constraints, here are some options:
Option 1: "Method overloading"
You need to pass extra information from your code to an existing method and act on it in a pre/post handler.
X++ doesn't support overloading methods – but you can mimic the behavior by creating a new method (with new name) in an extension class. The extension method can take additional parameters and call the original method; with your logic before and after calling the original method.
Here is an example of "overloading" the insert method on CustTable. Notice the first 3 parameters are identical to the parameters on the original insert() method.
Option 2: Class state
You need to pass extra information from your code to a method on a class that is called via other method(s) on the class.
X++ now supports adding class state via an extension. You can use this to store the extra information.
Here is an example adding state and wrapping a method.
Here is an example using this. The standard implementation of initFromItemOrCategory() calls initFromInventTable().
Option 3: Disposable context
You need to pass extra information from your code to a pre/post handler somewhere downstream.
It can be tempting to store the extra information in a global cache or variable. There is a better approach, which avoids stale data, and is type-safe. Create a singleton class for the context. The class must implement System.IDisposable, so it is disposed when it goes out of scope. The receiving code can access the singleton instance to extract the information.
Here is an example of the context class:
Here is an example of the calling code:
Here is an example of the consuming code. The standard implementation of CustTable.Insert() calls DirPartyTable::createNew() – the example uses Chain-of-command to wrap the createNew method, and then accesses the context to get the information.
Transferring state from one arbitrary place to another using a global variable (which the context class is) can lead to future logical errors – that can be very hard to detect and fix. My recommendation would be to limit the usage to situations where the scope and consequences are manageable.
Option 4: Request new extension points
Now, the above mechanisms cannot solve the cases where existing callers need to provide more data, or where the existing method implementation needs to act on the data. That would require overlayering. If you discover a need for this or another case where you are not comfortable with the above options, please log an extension request explaining your scenario. If you've read so far, it should now be obvious that you need more than changing a method's signature – you need an extension point, the implementation of this might require changing a method's signature – but that is just a technical detail.
P.S. If you have other suggestions for how to solve situations like these, please leave a comment.