title: How to allow for alternate valid enum values with XmlReader in .NET?
body: <p>I need to be able to make the <code>XmlReader</code>/<code>XmlSerializer</code> be ready to handle more than one possible value for an enum that it reads and properly translate it into the correct C# enum.   But I cannot figure out how to do this.</p>
  <p>Consider this LengthUnit enum (trimmed down to only 2 possible units for brevity)</p>
  <pre><code>public enum LengthUnit
  {
      Micron,
      Millimeter,
   }
  </code></pre>
  <p>My code writes and reads this just fine like this:</p>
  <pre><code>&lt;CurrentUnit&gt;Millimeter&lt;/CurrentUnit&gt;
  </code></pre>
  <p>but <em>reader</em> code needs be able to handle either of two possible values: &quot;Millimeter&quot; or &quot;mm&quot; and properly translate it into <code>LengthUnit.Millimeter</code>  So I need to be able to read either the above XML or the following:</p>
  <pre><code>&lt;CurrentUnit&gt;mm&lt;/CurrentUnit&gt;
  </code></pre>
  <p>Unfortunately when I try to read in a file with the latter, the XmlReader throws an InvalidOperationException</p>
  <pre><code>Exception of type: 'System.InvalidOperationException'  Message='Instance validation error: 'mm' is not a valid value for LengthUnit.'
  </code></pre>
  <p>I took at look the XmlEnum attribute to see if I could solve my problem with that, but it will only allow me to choose one name.  No alternate</p>
  <p>I did find <a href="https://docs.microsoft.com/en-us/dotnet/standard/serialization/how-to-specify-an-alternate-element-name-for-an-xml-stream" rel="nofollow noreferrer">this discussion about <em>writing</em> alternate <em>element</em> names</a> but I cannot seem to apply it to reading different enum values.</p>
  <p>Is this possible?  How would I go about it.  (Hell I'd even write my own custom <code>[XmlEnumAttribute2]</code> attribute if I could figure how.</p>
  <p><strong>[EDIT: Deserializer Code per request.   ]</strong></p>
  <p>Multiple class types derive from this abstract class and add their own properties to be serialized in XML.  I've not shown other members here.  The key point to remember is that some of those derived classes use the <code>LengthUnit</code> enum and (for reasons not germane to this question), sometimes those <code>LengthUnit</code> values are persisted with short names instead of the full names.</p>
  <p>I need to be able to handle that gracefully and I'd like to be able to handle it with out line-by-line handling of XML.</p>
  <pre><code>public abstract class SettingsBaseVm&lt;T&gt; : BaseVm where T : SettingsBaseVm&lt;T&gt;, new()
  {
      protected static T LoadImpl(string path, ILogger logger) 
      {
          // Handle events so partial reads still work.
  
          try
          {
              var events = new XmlDeserializationEvents
              {
                  OnUnknownAttribute   = (s, e) =&gt; logger.Warn($&quot;UserSettings: Unknown attribute {e.Attr.Name}&quot;),
                  OnUnknownElement     = (s, e) =&gt; logger.Warn($&quot;UserSettings: Unknown element {e.Element.Name}&quot;),
                  OnUnknownNode        = (s, e) =&gt; logger.Warn($&quot;UserSettings: Unknown node {e.Name}&quot;),
                  OnUnreferencedObject = (s, e) =&gt; logger.Warn($&quot;UserSettings: UnreferencedObject&quot;)
              };
              using var xmlReader = XmlReader.Create(path);
  
              xmlReader.MoveToContent();
              var deserializer  = new XmlSerializer(typeof(T));
              var settings      = deserializer.Deserialize(xmlReader, events) as T ?? throw new InvalidDataException(path);
              settings.Log      = logger; // So it can log errors
              settings.FilePath = path;
              settings.IsDirty  = false;
              return settings;
          }
          catch (Exception e) when (
              e is ArgumentException           ||
              e is IOException                 || 
              e is NotSupportedException       ||
              e is UnauthorizedAccessException ||
              e is SecurityException           ||
              e is FormatException             ||
              e is XmlException
          )
          {
              logger.Error(e);
              return new T() { Log = logger, FilePath = path };
  
          }
      }
  }
  </code></pre>