FAQ -- Frequently Asked Questions¶
Back to Index | Troubleshooting | Getting Started | Glossary
Do I need to use attributes or source generators¶
- No. You can implement
IUntargetedMessage<T>,ITargetedMessage<T>, orIBroadcastMessage<T>directly (recommended for structs). Attributes are optional and help tooling/source-gen.
Do I need an assembly definition for the source generator to work?¶
- No. The source generator and analyzers run for code in Unity's default
Assembly-CSharpand in your own assembly definitions alike, so you do not need to add an.asmdefjust to get generation. Mark the message typepartialand apply a[DxUntargetedMessage]/[DxTargetedMessage]/[DxBroadcastMessage]attribute (or implement the matchingI*Messageinterface). If generated members are missing, see Troubleshooting.
Which message type should I use?¶
- Untargeted - global notifications (any listener).
- Targeted - commands/events for a specific recipient.
- Broadcast - facts emitted from a source that others may observe.
Does DxMessaging allocate memory? Is dispatch zero-GC?¶
- Ordinary typed steady-state dispatch is allocation-free: emitting a struct message and invoking a typed registered handler allocates nothing after the first warm-up emit of that message type (a one-time JIT cost in the editor that IL2CPP precompiles away). The readonly by-reference (
FastHandler) handler overloads also avoid copying the struct on each call; the by-valueAction<T>overloads add one struct copy per dispatch but still do not allocate. Heap allocations come from constructing a class message instance. A struct message is boxed when it reaches a global accept-all handler or when user code upcasts it to a non-generic interface. Emission-site stack-trace capture also allocates while enabled. Registration itself allocates a small, bounded amount per handler (delegates and dictionary entries), so register handlers inAwake/setup rather than every frame. See Performance for measured numbers and Troubleshooting if you observe unexpected allocations.
How do I enforce ordering?¶
- Use the
priorityparameter at registration; lower runs earlier. Interceptors run before handlers; post-processors run after.
Can I observe all targets/sources for a type?¶
- Yes. Use
RegisterTargetedWithoutTargeting<T>orRegisterBroadcastWithoutSource<T>(and their post-processor counterparts).
How do I diagnose what's happening?¶
Enable Editor diagnostics, then choose the view that answers your question:
- Use Message Monitor to confirm that a message emitted, inspect its route kind and context, and open its captured call site.
- For loaded-scene
MessagingComponentreceivers, use Flow Graph to check whether a receiver registered for that message and whether the route has delivered calls. Direct bus or token registrations outside those components require bus logs or registration counters instead. - Use the Inspector overlay when a
MessageAwareComponentmay have missed a required base lifecycle call.
Start with Message Monitor. If the emission exists but a loaded-scene component receiver does not, move to Flow Graph to distinguish a missing registration from a route that has not delivered. The Diagnostics guide explains the tool scope, toggles, filters, trace capture, and release-build cost.
My MessageAwareComponent subclass does not receive messages. What is wrong?¶
The most common cause is forgetting to call base.Awake() (or base.OnEnable(), base.OnDisable(), base.OnDestroy(), base.RegisterMessageHandlers()) when you override one of those methods. The framework's setup runs in those base calls; without them, your registration token is never created or your handlers never enable. The Roslyn analyzer flags this as DXMSG006. See Inheritance and base calls for the full list of guarded methods.
What happens if I register a listener inside a message handler?¶
- The newly registered listener will not run for the current message emission. It will only become active starting with the next message emission.
- This is called "snapshot semantics" -- when a message is emitted, DxMessaging takes a snapshot of all current listeners and uses that frozen list for the entire emission.
- This applies to all listener types (handlers, interceptors, post-processors) and all message categories (Untargeted, Targeted, Broadcast).
- This behavior prevents infinite loops and ensures predictable execution order. See Interceptors & Ordering for details and examples.
Do I need a global bus?¶
- A global bus is provided (
MessageHandler.MessageBus). You can also create and pass your ownMessageBusinstance to isolate subsystems and tests.
Can I use DxMessaging with a dependency injection container?¶
- Yes. Installers ship for VContainer, Zenject, and Reflex; see Integrations. They wire the message bus into the container so your message-aware types resolve and register through it instead of reaching for the global bus.
How do I unit-test code that sends or receives messages?¶
- Construct a dedicated
MessageBusper test and pass it to the participants instead of using the global bus, so registrations cannot leak between tests. Emit a message, then assert your handler observed it. Isolating the bus also lets tests run in parallel without cross-talk.
Is this compatible with Unity's SendMessage/UnityEvents¶
- Yes. You can integrate with legacy patterns via
ReflexiveMessage. Prefer DxMessaging for new code.
Why is my game retaining memory across scenes?¶
- Each scene introduces new
InstanceIds and sometimes new message types, which add empty slots on the bus when their handlers tear down. Idle eviction will reclaim them eventually; for deterministic cleanup callMessageHandler.TrimAll(force: true)on scene unload (orbus.Trim(force: true)for a non-global bus). See the Memory Reclamation guide for the full pattern.
Related Documentation¶
- New to DxMessaging?
- to Visual Guide -- Beginner-friendly introduction
- to Getting Started -- Complete guide
- to Glossary -- All terms explained
- Common Issues
- to Troubleshooting -- Solutions to common problems
- to Common Patterns -- See how to use it correctly
- Reference
- to Quick Reference -- API cheat sheet
- to Message Types -- Which type to use when