Я пытался сериализировать a DynamicObject
класс с BinaryFormatter
, но:
Начиная с сериализации a DynamicObject
средства очень мало отдельно, вот класс, который я пытался сериализировать:
[Serializable()]
class Entity
: DynamicObject, ISerializable
{
IDictionary<string, object> values = new Dictionary<string, object>();
public Entity()
{
}
protected Entity(SerializationInfo info, StreamingContext ctx)
{
string fieldName = string.Empty;
object fieldValue = null;
foreach (var field in info)
{
fieldName = field.Name;
fieldValue = field.Value;
if (string.IsNullOrWhiteSpace(fieldName))
continue;
if (fieldValue == null)
continue;
this.values.Add(fieldName, fieldValue);
}
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
this.values.TryGetValue(binder.Name, out result);
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
this.values[binder.Name] = value;
return true;
}
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
foreach (var kvp in this.values)
{
info.AddValue(kvp.Key, kvp.Value);
}
}
}
(Я предполагаю, что, возможно, использовал ExpandoObject, но это - другая история.)
Вот простая тестовая программа:
static void Main(string[] args)
{
BinaryFormatter binFmt = new BinaryFormatter();
dynamic obj = new Entity();
dynamic subObj = new Entity();
dynamic obj2 = null;
obj.Value = 100;
obj.Dictionary = new Dictionary<string, int>() { { "la la la", 1000 } };
subObj.Value = 200;
subObj.Name = "SubObject";
obj.Child = subObj;
using (var stream = new FileStream("test.txt", FileMode.OpenOrCreate))
{
binFmt.Serialize(stream, obj);
}
using (var stream = new FileStream("test.txt", FileMode.Open))
{
try
{
obj2 = binFmt.Deserialize(stream);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
Console.ReadLine();
}
Помещение некоторых точек останова тут и там помогло мне взглянуть на obj2 содержание, и похоже, что исходные данные правильно десериализовываются, хотя с вышеупомянутыми недостатками, если Вы становитесь образными и перемещаете данные.
Я взглянул на protobuf-сеть Marc Gravell, но я не действительно уверен, как использовать ее в таком контексте (я даже не уверен, что поднял правильную версию из репозитория, но эй).
Я знаю, что это - больше кода, чем слова, но я не думаю, что могу объяснить сценарий немного лучше. Скажите, существует ли что-то, что я могу добавить для создания этого вопроса более ясным.
Любая справка очень ценится.
Я не уверен, будет ли JSON приемлемым в вашем сенарио, но если это так, я использовал Json.net ( http://json.codeplex.com ) для сериализации динамических типов. Работает неплохо, шустрый, на выходе небольшой размер. Хотя Json.net не возвращает динамические объекты напрямую, очень легко преобразовать десериализованный вывод Json.Net в любой динамический тип. В приведенном ниже примере я использую ExpandoObject в качестве динамического типа. Приведенный ниже код - это то, что я использовал в Facebook Graph Toolkit. См. Ссылку на первоисточник: http://facebookgraphtoolkit.codeplex.com/SourceControl/changeset/view/48442#904504
public static dynamic Convert(string s) {
object obj = Newtonsoft.Json.JsonConvert.DeserializeObject(s);
if (obj is string) {
return obj as string;
} else {
return ConvertJson((JToken)obj);
}
}
private static dynamic ConvertJson(JToken token) {
// FROM : http://blog.petegoo.com/archive/2009/10/27/using-json.net-to-eval-json-into-a-dynamic-variable-in.aspx
// Ideally in the future Json.Net will support dynamic and this can be eliminated.
if (token is JValue) {
return ((JValue)token).Value;
} else if (token is JObject) {
ExpandoObject expando = new ExpandoObject();
(from childToken in ((JToken)token) where childToken is JProperty select childToken as JProperty).ToList().ForEach(property => {
((IDictionary<string, object>)expando).Add(property.Name, ConvertJson(property.Value));
});
return expando;
} else if (token is JArray) {
List<ExpandoObject> items = new List<ExpandoObject>();
foreach (JToken arrayItem in ((JArray)token)) {
items.Add(ConvertJson(arrayItem));
}
return items;
}
throw new ArgumentException(string.Format("Unknown token type '{0}'", token.GetType()), "token");
}