如何感知Microsoft XmlSerializer对子对象的反序列化时机(多线程安全)
Great question—let’s break down your two proposed approaches, plus clarify why one is far more reliable than the other, all while keeping XmlSerializer’s automatic property deserialization intact.
Option 1: Thread-Local Storage (TLS) – The Recommended Approach
Since XmlSerializer executes deserialization single-threaded per operation, TLS is a perfect fit here—it avoids the thread-safety issues of global flags while giving you a per-thread indicator of whether deserialization is in progress.
Here’s how to implement it without disrupting your existing automatic deserialization:
- Add a static
ThreadLocal<bool>field to a base class (or a shared utility class) that all your serializable types inherit from:public class SerializableBase { private static readonly ThreadLocal<bool> _isDeserializing = new ThreadLocal<bool>(); [OnDeserializing] internal void OnDeserializing(StreamingContext context) { _isDeserializing.Value = true; } [OnDeserialized] internal void OnDeserialized(StreamingContext context) { _isDeserializing.Value = false; } // Helper property to check the state protected bool IsDeserializing => _isDeserializing.Value; } - Have your child classes inherit from this base class. Now, in any property setter or method of the child object, you can check
IsDeserializingto know if XmlSerializer is currently populating that object:public class ChildObject : SerializableBase { private string _name; public string Name { get => _name; set { if (IsDeserializing) { // Do something specific when XmlSerializer is setting this value Console.WriteLine("Name is being set during deserialization"); } _name = value; } } }
This works because:
- Each thread gets its own instance of
_isDeserializing, so there’s no cross-thread interference. - The
[OnDeserializing]and[OnDeserialized]callbacks are automatically invoked by XmlSerializer during the deserialization lifecycle, so you don’t have to write any custom serialization logic. - Your existing public properties stay fully compatible with XmlSerializer’s automatic deserialization.
Option 2: Call Stack Analysis – The Fragile Alternative
While call stack analysis can technically work, it’s not a long-term solution for a few key reasons:
- Brittleness: XmlSerializer’s internal method names or call stack structure can change between .NET versions (e.g., .NET Framework vs. .NET Core/.NET 5+), breaking your detection logic unexpectedly.
- Performance: Generating a full stack trace (
new StackTrace()) is relatively expensive, especially if you’re checking it frequently during deserialization of large object graphs.
If you still need to test this approach, here’s a rough example:
private bool IsInXmlDeserialization() { var stackTrace = new StackTrace(); foreach (var frame in stackTrace.GetFrames()) { var method = frame.GetMethod(); if (method.DeclaringType?.Namespace?.StartsWith("System.Xml.Serialization") == true && method.Name.Contains("Deserialize")) { return true; } } return false; }
Use this sparingly, and only if TLS isn’t feasible for some edge case.
Final Recommendation
Stick with the TLS approach—it’s thread-safe, reliable, and plays perfectly with XmlSerializer’s automatic deserialization workflow. Call stack analysis should be a last resort due to its inherent fragility.
内容的提问来源于stack exchange,提问作者Eric Ouellet

