我正在为我正在使用的一组系统编写一个不可知的查看器。该查看器将向我显示数据的通用结构,而无需了解特定系统的上下文。
我正在尝试反序列化仅包含类型 Foo<T>
的内存流其中 Foo<T>
继承自 Foo
.从不可知论者的角度来看,我需要的所有数据都在 Foo 中。 <T>
部分无关紧要。
类型 T 在另一个程序集中定义。在正常操作下,系统显然已加载所有适当的上下文程序集。问题是在运行查看器时,没有加载任何上下文程序集。当我尝试反序列化 Foo 的实例时,我显然会遇到异常,因为未加载引用的程序集。
我试图检测我是否加载了所有必需的引用程序集,从而知道是尝试反序列化数据,还是从类的其他方面重建我需要的数据。
我知道我可以使用一个非常简单的异常 try/catch block 来做到这一点,但这不是异常情况。我知道当我加载我的数据时,这将发生数百次,如果不是数千次,这可能会给我带来噩梦,因为我喜欢打开异常中断。我也赞同“异常 - 提示在名称中”的思想流派,因此异常不应构成主要案例代码的一部分。
--------编辑 21/10/2013------------
参见 here一个完整的说明性例子,但这里是重要的部分:
Foo 类,共同定义:
[Serializable]
public class Foo
{
public string Agnostic { get; set; }
}
[Serializable]
public class Foo<T> : Foo
{
public string Contextual { get; set; }
}
上下文保存:
BinaryFormatter bf = new BinaryFormatter();
FileInfo tempFile = TempFileGetter.GetTempFile();
Foo<Bar> fooBar = new Foo<Bar>();
fooBar.Agnostic = "Agnostic";
fooBar.Contextual = "Contextual";
using (var fs = tempFile.OpenWrite())
{
bf.Serialize(fs, fooBar);
fs.Flush();
}
不可知加载:
BinaryFormatter bf = new BinaryFormatter();
FileInfo tempFile = TempFileGetter.GetTempFile();
using (var fs = tempFile.OpenRead())
{
Foo foo = (Foo)bf.Deserialize(fs);
Controls.DataContext = foo;
}
我的意思是,这段代码中没有什么火箭科学,而且,如果“不可知论者”查看器加载上下文查看器作为引用,那么它加载正常,但是,我不想这样做,因为我们赢了' 始终加载上下文库。
最佳答案
我所做的是创建一个序列化容器,它分析它的内容以查看需要哪些引用并单独序列化:
[serializable]
public class Container
{
private IEnumerable<object> data;
public Container(IEnumerable data);
public string[] GetFullyQualifiedReferences();
}
因此,您可以将所需的任何数据放入此处,并获得一个完全限定的程序集名称列表,然后将其单独存储。
假设 Wibble
是序列化 Foo 的类
public class Wibble : ISerializable
{
public string Agnostic { get { return agnostic; } }
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
//construct a container based on my data.
Container container = new Container(new object[]{myFoo});
info.AddValue("RequiredReferences",container.GetFullyQualifiedReferences());
byte[] containerData = Serialize(container);
info.AddValue("TypeUnsafeData",containerData);
//store some safe typed versions of the context data, if necessary.
info.AddValue("SafeValues", GetSafeValues())
}
public Wibble(SerializationInfo info, StreamingContext context)
{
var requiredAssemblies =
(string[])info.GetValue("RequiredReferences",typeof(string[]));
if(AreAssembliesLoaded(requiredAssemblies )))
{
//deserialise the container as normal
}
else
{
//instead, load the "safe" data that we previously stored.
}
}
}
我知道根据插图这并不完全合理,但插图是对我的实现问题的稍微不完美的抽象,但解决方案应该适用于两者(我知道它适用于我的实现!)
您可以进行下一步,让容器中的容器列出任何容器所需的特定程序集,但这在本图中并不是真正必需的。
------更新--------
目前这个实现有一个小问题,那就是如果你更新上下文程序集版本号,反序列化器将找不到旧程序集。所以,您要么需要:
提供某种机制允许反序列化代码查看它是否可以找到程序集的现代版本然后查询它,
---或者---
更新完全限定名称的相等性以对版本控制不敏感。
关于c# - 缺少反序列化引用时不抛出异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19446028/