On this page

19. Events

19.1 Declaration and callable type

CS-EVENT-001. An event declares a .NET-compatible multicast callable signature. EventArgs is not required. Normal applicable accessibility and member modifiers apply. A handler must have a compatible callable/delegate signature.

public class ImportProgress
    public event ProgressChanged(completed as Integer, total as Integer)

    public action Report(completed as Integer, total as Integer)
        require completed >= 0
        require total >= completed

        raise_event ProgressChanged(completed, total)
    end action
end class

CS-EVENT-002. Only the declaring type may raise an event. raise_event is distinct from invoking an ordinary callable. Imported events keep their .NET access restrictions. Events do not acquire an asynchronous delivery, dispatcher, priority or weak-reference policy merely because they are declared in DirectSharp.

19.2 Imperative subscription

CS-EVENT-003. Imperative add/remove identifies the event explicitly:

public action ShowImport(progress as ImportProgress)
    action DisplayProgress(completed as Integer, total as Integer)
        Global.System.Console.WriteLine("Imported {{completed}} of {{total}}")
    end action

    event progress.ProgressChanged add_handler DisplayProgress
    try
        progress.Report(0, 100)
        progress.Report(100, 100)
    finally
        event progress.ProgressChanged remove_handler DisplayProgress
    end try
end action

The same syntax applies to imported .NET events. Removal uses the compatible handler identity/value originally subscribed. A newly created lambda with the same text is not automatically the same subscribed delegate. Imperative subscription lifetime is programmer-managed.

19.3 Declarative handlers

CS-EVENT-004. handles_event source.Event on an action declares compiler-managed subscription. The source must be a stored, deterministically trackable field, property, need, receiver-reachable member or static source. A transient call such as GetProgress().ProgressChanged is invalid as a declarative source.

public class ProgressDisplay
    needs
        replaceable progress as ImportProgress
    end needs

    private action Display(completed as Integer, total as Integer)
        handles_event progress.ProgressChanged

        Global.System.Console.WriteLine("Imported {{completed}} of {{total}}")
    end action
end class

CS-EVENT-005. When a tracked source changes, generated management unsubscribes from the old non-absent source, updates the reference and subscribes to the new non-absent source in that order. An absent source has no active subscription. Declarative handlers are managed for the containing object's lifetime and unwired as required by its disposal/lifetime contract. No WithEvents modifier is needed.

19.4 Reference C# lowering and failures

Imperative subscription and raising have the normal CLR shapes:

progress.ProgressChanged += DisplayProgress;
try
{
    progress.Report(0, 100);
    progress.Report(100, 100);
}
finally
{
    progress.ProgressChanged -= DisplayProgress;
}

In reference C#, a declaring type can implement raising as ProgressChanged?.Invoke(completed, total). The synchronous multicast event uses ordinary .NET delegate invocation behavior: no handler means no invocation; handlers run through the multicast invocation list; an unhandled handler exception propagates rather than automatically dispatching the remaining handlers. Explicit framework dispatch or exception isolation must be expressed by ordinary code or a library.

The complete event reference supplies stored-source and imperative observation sessions, a direct BindingList example, delegate identity/raise boundaries and matching private C# fragments. It separates explicit session detachment from compiler-generated lifetime plumbing and imported accessor integration.

Reject incompatible handler signatures, inaccessible event access, raising an event outside its declaring type, and untrackable declarative source expressions. Async event semantics, weak events, custom accessors, event buses and special dispatch policies are outside the core event contract.


Specification contents · Previous: 18. Lazy values · Next: 20. Dependency injection and services