"A public Reset() on a Component silently shadows the engine's Component.Reset()"
▸ SYMPTOM
- You add
public void Reset()to aComponentto clear its own state. It compiles clean and the build gate goes green. - Depending on the call site, the wrong
Reset()runs — either your state-clearing code or the engine's lifecycle reset — and the mismatch is silent. - A quiet-verbosity build (
dotnet build -v q) shows nothing wrong; there's no error and no visible warning.
▸ CAUSE
Component already has a Reset() method. When you declare public void Reset() on your own component without the new keyword, C# treats it as member hiding — your method shadows the inherited one. The compiler flags this, but only as a CS0114 warning:
'MyComponent.Reset()' hides inherited member 'Component.Reset()'. Use the new keyword if hiding was intended.
The trap is the build gate. Warnings don't print at quiet verbosity (-v q) — only errors do. So a gate that checks for a clean/green build treats a CS0114 collision exactly like a warning-free compile. Green is not the same as warning-free.
Because the method is hidden (not overridden), which Reset() runs for a given call depends on the compile-time type of the reference at the call site. Code holding a Component reference calls the engine's version; code holding your concrete type calls yours. An author who reaches for Reset as the natural name for "clear my own state" silently collides with lifecycle machinery that expects to own that name.
▸ FIX
Don't name a Component method after an engine lifecycle method unless you deliberately mean to hook it. Pick a different name:
// AVOID — silently hides Component.Reset(), only a CS0114 warning:
public void Reset() { /* clear my state */ }
// PREFER — an unambiguous name that can't collide:
public void ResetState() { /* clear my state */ }
// or Clear(), ClearState(), etc.If you genuinely intend to hide the base member, say so explicitly with new (or override if the base member is virtual and you mean to override it) — so the intent is in the code, not an accident.
▸ WHY IT WORKS
The collision is a naming problem, so a distinct name removes it entirely — there's no inherited member to shadow, no CS0114, and no dependence on the reference's compile-time type. To catch the case where you do reuse a lifecycle name, don't trust a quiet-verbosity gate as proof of a clean compile for a new component:
- Read the actual warning list at normal or higher verbosity at least once per new component, or
- Grep new component source for method names that collide with
Component's own public/protected surface.
- Published.