Implement delegates

Completed

When you’re creating extensible solutions, you can use delegates by subscribing to the delegate in X++.

Delegates are composite data types that are part of how finance and operations apps can create extensions. You can define delegates on a method. Then, when the method is called, it'll also call their subscriber methods.

We don’t recommend that you create new delegates in the application. Rather, we recommend that you subscribe to existing delegates and then use Chain of Command (CoC), which provides a richer, more robust, and more concise extension mechanism that supersedes delegates.

Instead of creating delegates, structure your code into smaller methods so that you can use it in CoC.

If you use delegates, they’ll typically reside in the middle of a method because, if pre-events and post-events are present and CoC is used, they’ll be in the beginning and end of a method, respectively.

You can use delegates in the standard finance and operations apps, and they’re useful for independent software vendor (ISV) solutions.

Delegates in X++ must have the void return type. Also, delegates can be static and instance methods, and they can use the EventHandlerResult as a method parameter to return a result.

Subscribers for delegates aren’t in control of the implementation order.

Create delegates

Typically, you would create delegates in your code in tables, forms, or classes.

Make sure that you define the delegate in the code and then ensure that you define a call to the empty delegate so that subscribers can use it.

The following code sample shows how a delegate might appear in a class:

/// <summary>
    /// Delegate for construct <c>MyCustTableClass</c> instances.
    /// </summary>
    /// <param name = "_buffer">The buffer to create the instance from.</param>
    /// <param name = "_eventHandlerResult">An <c>EventHandlerResult</c></param>
    static delegate void constructDelegate(Common _buffer,EventHandlerResult _eventHandlerResult)
    {
    }

You would call the delegates in the code as follows:

/// <summary>
    /// Construct method <c>MyCustTableClass</c> instances.
    /// </summary>
    /// <param name = "_buffer">The buffer to create the instance from.</param>
    /// <returns>
    /// MyCustTableClass.
    /// </returns>
    public static MyCustTableClass construct(Common _buffer)
    {
        switch (_buffer.TableId)
        {
            case tablenum(CustTable):
                return new MyCustTableClass(_buffer);

            default:
                EventHandlerResult result = EventHandlerResult::newSingleResponse();
                MyCustTableClass::constructDelegate(_buffer, result);
                if (result.hasResult())
                {
                    return result.result() as MyCustTableClass;
                }
                break;
        }

        throw error(Error::missingRecord(classstr(MyCustTableClass)));
    }

As shown in the preceding example, the call to the static MyCustTableClass::constructDelegate is done in the middle of the method, so you can’t use pre-events and post-events or CoC. Because you’ve created delegates, an extension is now enabled.

The system uses the EventHandlerResult to return the result, which you can validate.

Subscribe to a delegate

You can perform extensions by subscribing to the delegate, which enables you to make modifications, as the following code sample shows:

/// <summary>
    /// <c>MyCustTableClass</c> class delegate subscriber.
    /// </summary>
    [SubscribesTo(classstr(MyCustTableClass), staticDelegateStr(MyCustTableClass, constructDelegate))]
    public static void myConstruct(Common _buffer, EventHandlerResult _eventHandlerResult)
    {
        CustTable custTable = _buffer as CustTable;

        // do something

        _eventHandlerResult.result(custTable);
    }

Subscribers use the SubscribesTo attribute with the class name and delegate method name, and the system uses the EventHandlerResult method to set the desired result.

Using delegates can be useful, but the best practice is to use CoC because it provides a richer, more robust, and more concise extension mechanism. Additionally, you can apply CoC by splitting and structuring code into smaller pieces.