我需要将一个未标记为可序列化(serializable)属性的对象持久化。这个对象是来自于第三方库,无法进行更改。
我需要将它存储在一个持久化的地方,比如说文件系统,那么最优解决方案就是将对象序列化到一个文件中,但由于它没有被标记为可序列化,这并不是一个直接的解决方案。
这是一个非常复杂的对象,也包含了其他对象的集合。
你们有任何解决方法吗?代码永远不会在生产环境中运行,所以我可以接受几乎任何解决方案和性能。
我需要将一个未标记为可序列化(serializable)属性的对象持久化。这个对象是来自于第三方库,无法进行更改。
我需要将它存储在一个持久化的地方,比如说文件系统,那么最优解决方案就是将对象序列化到一个文件中,但由于它没有被标记为可序列化,这并不是一个直接的解决方案。
这是一个非常复杂的对象,也包含了其他对象的集合。
你们有任何解决方法吗?代码永远不会在生产环境中运行,所以我可以接受几乎任何解决方案和性能。
XmlSerializer
可能是一个有用的尝试,如果类型是公共的等等。
如果失败了,protobuf-net的v2版本(正在进行中,您需要从源代码构建,但我可以帮助)可以处理未经注释的对象,因此非常适合控制范围之外的类型,您只需要告诉它要包含什么(通过DSL)。 v2代码尚未完成,但它涵盖了大多数常见场景,包括集合等(未完成的工作主要是回调和枚举)。
FormatterServices.GetUninitializedObject
)。 - Marc GravellFormatterServices.GetUninitializedObject
的技巧。我正在构建一组快速方法,但是无法想出如何创建没有无参构造函数的对象。这真是个巧妙的技巧...谢谢! - Matthew Whited.GetFields(...)
方法。
另一个想法...
如果你只是为了加快开发速度而这样做,为什么不使用自己的适配器类来包装他们的类。这将允许你用自己简化的模拟类替换第三方库,并为后续的替换和重用提供更好的机会。
虽然这很疯狂...但比我想象的要容易得多。(虽然这有效,但请考虑使用适配器来包装第三方类。)public static class Tools
{
public static XElement AsXml(this object input)
{
return input.AsXml(string.Empty);
}
public static XElement AsXml(this object input, string name)
{
if (string.IsNullOrEmpty(name))
name = input.GetType().Name;
var xname = XmlConvert.EncodeName(name);
if (input == null)
return new XElement(xname);
if (input is string || input is int || input is float /* others */)
return new XElement(xname, input);
var type = input.GetType();
var fields = type.GetFields(BindingFlags.Instance |
BindingFlags.NonPublic)
.Union(type.GetFields(BindingFlags.Instance |
BindingFlags.Public));
var elems = fields.Select(f => f.GetValue(input)
.AsXml(f.Name));
return new XElement(xname, elems);
}
public static void ToObject(this XElement input, object result)
{
if (input == null || result == null)
throw new ArgumentNullException();
var type = result.GetType();
var fields = type.GetFields(BindingFlags.Instance |
BindingFlags.NonPublic)
.Union(type.GetFields(BindingFlags.Instance |
BindingFlags.Public));
var values = from elm in input.Elements()
let name = XmlConvert.DecodeName(elm.Name.LocalName)
join field in fields on name equals field.Name
let backType = field.FieldType
let val = elm.Value
let parsed = backType.AsValue(val, elm)
select new
{
field,
parsed
};
foreach (var item in values)
item.field.SetValue(result, item.parsed);
}
public static object AsValue(this Type backType,
string val,
XElement elm)
{
if (backType == typeof(string))
return (object)val;
if (backType == typeof(int))
return (object)int.Parse(val);
if (backType == typeof(float))
return (float)int.Parse(val);
object ret = FormatterServices.GetUninitializedObject(backType);
elm.ToObject(ret);
return ret;
}
}
public class Program
{
public static void Main(string[] args)
{
var obj = new { Matt = "hi", Other = new { ID = 1 } };
var other = new { Matt = "zzz", Other = new { ID = 5 } };
var ret = obj.AsXml();
ret.ToObject(other);
Console.WriteLine(obj); //{ Matt = hi, Other = { ID = 1 } }
Console.WriteLine(other); //{ Matt = hi, Other = { ID = 1 } }
}
}
我不知道这对你的使用是否过于复杂,但我最近一直在尝试使用db4o。它可以持久化任何对象,只需调用IObjectContainer.Store(object)即可,而且它非常轻量级且基于文件。不需要安装。
目前为止,我还没有遇到任何问题。
///Here OBJECT is Class name and Object_to_write is instance
XmlSerializer serializer = new XmlSerializer(typeof(OBJECT));
using (TextWriter writer = new StreamWriter(@"C:\Xml.xml"))
{
serializer.Serialize(writer, OBJECT_to_Write);
}