This document describes the PX1079 diagnostic.
| Code | Short Description | Type | Code Fix |
|---|---|---|---|
| PX1079 | Methods with the PXOverride attribute must have an additional delegate parameter for calling base methods. |
Error | Available |
A method with the PXOverride attribute must have an additional delegate parameter for calling the base method. Acumatica Framework supports two ways to override a method with the PXOverride attribute which are applied depending on the case:
- A method with the
PXOverrideattribute has the same signature as the base method. In this case, the base method is replaced at run time with the Override Methods Queue, which starts with the base method. The system adds methods that have thePXOverrideattribute and the same signature as the base method to this queue. When the system invokes the base method, all methods in the queue are executed sequentially, starting with the one that was added to the queue first. - A method with the
PXOverrideattribute has the same name, return type, and parameters as the base method plus an additional parameter. This last parameter is a delegate that represents the base method. The signature of this delegate must match the signature of the base method. The purpose of this delegate is to provide developers with control of calls to the base method from the overriding method. In the delegate parameter, the system passes a reference to the override method with an additional parameter from the graph extension of the previous level, if such a method exists. If there is no such override method, then the system passes a reference to the Override Methods Queue from the previous point, if such queue exists. If there is no Override Methods Queue, then the system passes a reference to the virtual base method.
However, the practice has shown that the use of the Override Methods Queue mechanism is difficult in most scenarios except the most trivial ones due to the following reasons:
- The lack of control over the order of method execution in the queue makes it difficult to predict the behavior of the system in case the same method is overridden in multiple independent customizations.
- For
virtualmethods with non-voidreturn types, it is impossible to predict what value will be returned by the method in the queue, because the return value of the method is determined by the last method in the queue. - For some special return types the situation is even worse:
- For methods with the
IEnumerable<T>return type, only the sequence returned by the last override method in the queue will be enumerated. This means that the previous methods in the queue will not be executed at all. - For methods with the
TaskandTask<T>return type, only the task returned by the last override method can be awaited. Tasks returned by other override methods in the queue will not be awaited. This can lead to an unexpected execution of multiple async override methods at the same time, which can cause hard to reproduce bugs.
- For methods with the
Due to the reasons listed above, Acumatica decided to discourage the use of the Override Methods Queue mechanism and to recommend using the second way of overriding methods with the PXOverride attribute.
The code fix for the PX1079 diagnostic adds an additional delegate parameter to the method with the PXOverride attribute. The type of this parameter matches the signature of the base method.
The name of the delegate parameter is generated according to the naming conventions of Acumatica Framework. The convention is to name the delegate parameter as base_<MethodName>, where <MethodName> is the name of the base method being overridden.
The code fix does not support methods that accept an input value or the return result by reference instead of by value, such as:
- Methods with the
ref,out,in, orref readonlyparameters - Methods with the
refandref readonlyreturn types
Such methods have to be fixed manually.
- The overriding method must be declared in a graph extension.
- The overriding method must have the
publicaccess modifier. - The overriding method cannot be
virtual,abstract, oroverride. - The overriding method should not be
static. - The overriding method cannot be a generic method.
- The overriding method should declare an XML documentation comment with a reference to the base method in the format
/// Overrides <seealso cref="{Base method}">. - The signature of the overriding method must be compatible with the signature of the overridden base method. The names of the derived method and the base method must match.
- The base method must be
virtual(have eithervirtualoroverridemodifiers). - The base method must have one of the following accessibility levels:
public,protected, orprotected internal.
The following example demonstrates a correct declaration of the PXOverride method with an additional delegate parameter.
public class MyGraph : PXGraph<MyGraph>
{
}
public class BaseGraphExtension : PXGraphExtension<MyGraph>
{
public virtual int Add(int x, string y)
{
return x + Convert.ToInt32(y);
}
}
public class DerivedGraphExtension : PXGraphExtension<BaseGraphExtension, MyGraph>
{
/// Overrides <seealso cref="BaseGraphExtension.Add(int, string)"/>
[PXOverride]
public int Add(int x, string y, Func<int, string, int> base_Add)
{
if (x < 10)
{
return x + Convert.ToInt32(y) * 2;
}
return base_Add(x, y);
}
}In the following example, PXOverride methods are declared without an additional delegate parameter.
public class MyGraph : PXGraph<MyGraph>
{
protected virtual void UpdateBalances()
{
// Implementation
}
}
public class BaseGraphExtension : PXGraphExtension<MyGraph>
{
public virtual int Add(int x, string y)
{
return x + Convert.ToInt32(y);
}
}
public class DerivedGraphExtension : PXGraphExtension<BaseGraphExtension, MyGraph>
{
/// Overrides <seealso cref="BaseGraphExtension.Add(int, string)"/>
[PXOverride]
public int Add(int x, string y) // Report PX1079
{
if (x < 10)
{
return x + Convert.ToInt32(y) * 2;
}
return base_Add(x, y);
}
/// Overrides <seealso cref="MyGraph.UpdateBalances()"/>
[PXOverride]
public void UpdateBalances() // Report PX1079
{
// Implementation
}
}