获取引发 SerializationException 的 属性 的名称

Get name of a property which raizes SerializationException

我使用 BinaryFormatter 序列化大型复杂对象,一些 属性 的序列化导致 SerializationException。我如何获取有关 属性 导致错误的信息?

当然,我可以获得无法序列化的类型的名称,但是我找不到包含该类型实例的属性。

异常消息如下所示:

Type "MyType" from assembly "MyAssembly" is not marked as serializable.

此类型的实例不应存在于序列化的对象中,我找不到包含它的 属性。

为了序列化,我使用了这个简单的代码(其中数据是我的复杂类型的一个实例):

...
var str = new MemoryStream();
var bf= new BinaryFormatter();
bf.Serialize(stream, data);
...

您需要在您尝试序列化的 class 上添加可序列化标签。

这是一个例子。我有一个 class 名称 Point2D,它具有一些属性和序列化标签。

[Serializable]
public class Point2D
{
    [XmlAttribute]
    public double X { get; set; }

    [XmlAttribute]
    public double Y { get; set; }
}

这是序列化代码。

var point2D = new Point2D { X = 2, Y = 3 };
var stream = new MemoryStream();
var bf= new BinaryFormatter();
bf.Serialize(stream, point2D);

嗯,对象已经用反射找到了

private bool TrySerialize(object obj)
{
    if (obj == null)
        return true;
    var stream = new MemoryStream();
    var bf = new BinaryFormatter();
    try
    {
        bf.Serialize(stream, obj);
    }
    catch (SerializationException)
    {
        return false;
    }
    return true;
}
private string FindObject(Stack<object> self, Type typeToFind, string path)
{
    var _self = self.Peek();
    if (self.Where(x => x.Equals(_self)).Count() > 1) return null;
    foreach (var prop in _self.GetType().GetMembers().Where(x => !x.GetCustomAttributes(true).Any(y => y is XmlIgnoreAttribute)))
    {
        switch (prop.MemberType)
        {
            case System.Reflection.MemberTypes.Property:
                {
                    var line = string.Format("{0}::{1}", path, prop.Name);
                    var _prop = prop as PropertyInfo;

                    if (_prop.GetIndexParameters().Count() > 0) break;

                    if (typeToFind.IsAssignableFrom(_prop.PropertyType))
                        return line;


                    if (_prop.PropertyType.IsPrimitive || _prop.PropertyType == typeof(DateTime) || _prop.PropertyType == typeof(string))
                        continue;

                    var subInst = _prop.GetValue(_self, new object[0]);
                    if (subInst == null)
                        continue;

                    if (!TrySerialize(subInst))
                    {
                        System.Diagnostics.Debugger.Log(0,"",string.Format("Cannot serialize {0}\n", line));
                    }

                    self.Push(subInst);
                    var result = FindObject(self, typeToFind, line);
                    self.Pop();
                    if (result != null)
                        return result;
                }
                break;
            case System.Reflection.MemberTypes.Field:
                {
                    var line = string.Format("{0}::*{1}", path, prop.Name);
                    var _prop = prop as FieldInfo;

                    if (typeToFind.IsAssignableFrom(_prop.FieldType))
                        return line;

                    if (_prop.FieldType.IsPrimitive || _prop.FieldType == typeof(DateTime) || _prop.FieldType == typeof(string))
                        continue;

                    var subInst = _prop.GetValue(_self);
                    if (subInst == null)
                        continue;

                    if (!TrySerialize(subInst))
                    {
                        System.Diagnostics.Debugger.Log(0, "", string.Format("Cannot serialize field {0}\n", line));
                    }

                    self.Push(subInst);
                    var result = FindObject(self, typeToFind, line);
                    self.Pop();
                    if (result != null)
                        return result;
                }
                break;

            case System.Reflection.MemberTypes.Event:
                {
                    var line = string.Format("{0}::!{1}", path, prop.Name);
                    var _prop = prop as EventInfo;


                    if (typeToFind.IsAssignableFrom(_prop.EventHandlerType))
                        return line;

                    var field =  _self.GetType().GetField(_prop.Name,
                        BindingFlags.NonPublic |BindingFlags.Instance |BindingFlags.GetField);


                    if (field!=null && !field.GetCustomAttributes(true).Any(x=>x is NonSerializedAttribute) 
                        && !TrySerialize(field.GetValue(_self)))
                    {
                        System.Diagnostics.Debugger.Log(0, "", string.Format("Cannot serialize event {0}\n", line));
                    }


                }
                break;

            case System.Reflection.MemberTypes.Custom:
                {

                }
                break;
            default: break;
        }


    }
    if (_self is IEnumerable)
    {
        var list = (_self as IEnumerable).Cast<object>();
        var index = 0;
        foreach (var item in list)
        {
            index++;
            self.Push(item);
            var result = FindObject(self, typeToFind, string.Format("{0}[{1}]", path, index));
            self.Pop();
            if (result != null)
                return result;
        }
    }

    return null;
}

要这样调用:

string result = FindObject(new Stack<object>(new object[] { instanceToSearchIn }), typeof(MyType), "[myself]");

结果我得到了:

[myself]::RootSection::Children[0]::Children[0]::Item

更新:

此代码现在还测试成员的序列化