Comme @Marc dit, le format de fil n'envoie données pour les éléments, donc afin de savoir si la liste était vide ou nulle, vous devez ajouter ce bit d'information dans le flux.
Ajout d'un bien supplémentaire pour indiquer si la collection originale était vide ou non est facile, mais si vous ne voulez pas modifier la définition du type d'origine, vous avez une autre deux options:
sérialisation En utilisant Surrogate
Le type de substitution aura la propriété supplémentaire (gardant votre type d'origine intact) et restaurera l'état d'origine de la liste: null, avec des éléments ou vide.
[TestMethod]
public void SerializeEmptyCollectionUsingSurrogate_RemainEmpty()
{
var instance = new SomeType { Items = new List<int>() };
// set the surrogate
RuntimeTypeModel.Default.Add(typeof(SomeType), true).SetSurrogate(typeof(SomeTypeSurrogate));
// serialize-deserialize using cloning
var clone = Serializer.DeepClone(instance);
// clone is not null and empty
Assert.IsNotNull(clone.Items);
Assert.AreEqual(0, clone.Items.Count);
}
[ProtoContract]
public class SomeType
{
[ProtoMember(1)]
public List<int> Items { get; set; }
}
[ProtoContract]
public class SomeTypeSurrogate
{
[ProtoMember(1)]
public List<int> Items { get; set; }
[ProtoMember(2)]
public bool ItemsIsEmpty { get; set; }
public static implicit operator SomeTypeSurrogate(SomeType value)
{
return value != null
? new SomeTypeSurrogate { Items = value.Items, ItemsIsEmpty = value.Items != null && value.Items.Count == 0 }
: null;
}
public static implicit operator SomeType(SomeTypeSurrogate value)
{
return value != null
? new SomeType { Items = value.ItemsIsEmpty ? new List<int>() : value.Items }
: null;
}
}
Faites vos types Extensible
protobuf-net suggère l'interface IExtensible qui vous permettent d'étendre les types de sorte que les champs peuvent être ajoutés à un message sans rien casser (en savoir plus here) . Pour utiliser l'extension protobuf-net, vous pouvez hériter de la classe Extensible
ou implémenter l'interface IExtensible
pour éviter les contraintes d'héritage.
Maintenant que votre type est "extensible", vous définissez les méthodes [OnSerializing]
et [OnDeserialized]
pour ajouter les nouveaux indicateurs qui seront sérialisés au flux et désérialisés lors de la reconstruction de l'objet avec son état d'origine. Les avantages sont que vous n'avez pas besoin de définir de nouvelles propriétés ni de nouveaux types comme substituts, par contre IExtensible
n'est pas supporté si votre type a des sous-types définis dans votre modèle de type.
[TestMethod]
public void SerializeEmptyCollectionInExtensibleType_RemainEmpty()
{
var instance = new Store { Products = new List<string>() };
// serialize-deserialize using cloning
var clone = Serializer.DeepClone(instance);
// clone is not null and empty
Assert.IsNotNull(clone.Products);
Assert.AreEqual(0, clone.Products.Count);
}
[ProtoContract]
public class Store : Extensible
{
[ProtoMember(1)]
public List<string> Products { get; set; }
[OnSerializing]
public void OnDeserializing()
{
var productsListIsEmpty = this.Products != null && this.Products.Count == 0;
Extensible.AppendValue(this, 101, productsListIsEmpty);
}
[OnDeserialized]
public void OnDeserialized()
{
var productsListIsEmpty = Extensible.GetValue<bool>(this, 101);
if (productsListIsEmpty)
this.Products = new List<string>();
}
}