为简单起见,我将使用水果展示我的示例代码。实际上我正在做一些更有意义的事情(我们希望)。假设我们有一个枚举:
public enum FruitType
{
Apple,
Orange,
Banana
}
一堂课:
[Serializable]
public class Fruit
{
public FruitType FruitType { get; set; }
public Fruit(FruitType type)
{
this.FruitType = type;
}
}
我们可以对它进行序列化和反序列化。现在,让我们修改枚举,现在就是:
public enum FruitType
{
GreenApple,
RedApple,
Orange,
Banana
}
在反序列化以前序列化的对象时,会出现System.InvalidOperation
异常,因为Apple
(原始枚举项)无效。该对象不会被反序列化。
我能够解决这个问题的一种方法是在FruitType
类的Fruit
属性被序列化时给出一个不同的名称,如下所示:
[XmlElement(ElementName = "Mode")]
public FruitType FruitType { get; set; }
现在,在反序列化期间,旧属性会被忽略,因为找不到它。我想知道是否有一种方法可以在反序列化期间忽略/跳过无效的枚举项,这样就不会抛出异常并且对象仍然会被反序列化。
答案 0 :(得分:3)
退出Apple
并使用ObsoleteAttribute
进行标记。这样,使用Apple
的任何代码都会生成编译器警告。
答案 1 :(得分:1)
我自己一直在寻找类似的答案,并且当XML包含无效的枚举值时,编写此代码以捕获异常。它删除该元素,并尝试再次反序列化。如果元素是必需的,您仍然会得到一个例外。这是不完美的,但应该让你大部分时间到达你想去的地方
private const string XmlError = "There is an error in XML document ";
private const string InstanceValidationError = "Instance validation error:";
private static readonly Regex XmlErrorRegex = new Regex("There is an error in XML document \\((\\d+), (\\d+)\\).");
private static readonly Regex InstanceValidationErrorRegex = new Regex("Instance validation error: '(\\S+)' is not a valid value for (\\S+).");
private const string TagFinderString = "\\>{0}\\</(\\S+)\\>";
/// <summary>
/// Helper method to deserialize xml message
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="message"></param>
/// <returns></returns>
public T Deserialize(string message)
{
var result = default(T);
if (!string.IsNullOrEmpty(message))
{
using (var reader = new StringReader(message))
{
try
{
result = (T)_serializer.Deserialize(reader);
}
catch (InvalidOperationException ex)
{
if (ex.Message.StartsWith(XmlError))
{
if(ex.InnerException != null && ex.InnerException.Message.StartsWith(InstanceValidationError))
{
var instanceValidationErrorMatches = InstanceValidationErrorRegex.Matches(ex.InnerException.Message);
if (instanceValidationErrorMatches.Count > 0)
{
var locationMatches = XmlErrorRegex.Matches(ex.Message);
var startIndex = GetStartIndex(message, locationMatches);
var match = instanceValidationErrorMatches[0];
if(match.Groups.Count > 0)
{
var toRemove = GetToRemove(message, match, startIndex);
return Deserialize(message.Replace(toRemove, string.Empty));
}
}
}
}
}
}
}
return result;
}
private static string GetToRemove(string message, Match match, int startIndex)
{
var value = match.Groups[1];
var tagFinder = new Regex(string.Format(TagFinderString, value));
var tagFinderMatches = tagFinder.Matches(message.Substring(startIndex));
var tag = tagFinderMatches[0].Groups[1];
return string.Format("<{0}>{1}</{0}>", tag, value);
}
private static int GetStartIndex(string message, MatchCollection locationMatches)
{
var startIndex = 0;
if (locationMatches.Count > 0)
{
var lineNumber = int.Parse(locationMatches[0].Groups[1].Value);
var charIndex = int.Parse(locationMatches[0].Groups[2].Value);
using (var locationFinder = new StringReader(message))
{
for (var i = 1; i < lineNumber; i++)
{
startIndex += locationFinder.ReadLine().Length;
}
}
startIndex += charIndex;
}
return startIndex;
}
答案 2 :(得分:0)
我发布了一个similar question并且没有找到一个简单的方法来捕获反序列化器在XML文件中遇到Apple时抛出的异常。在反序列化期间,我可以在缺少属性或元素时捕获一堆其他异常,但不能用于无效的枚举值。无效的枚举值(在您的情况下是Apple)使我摆脱了反序列化。
一种可能的解决方案是在Fruit类上实现IXMLSerializable。当反序列化器调用IXMLSerailizable.ReadXML()方法时,您必须查看传递给您的内容。当值为“Apple”时,根据某些逻辑将枚举设置为GreenApple或RedApple。