You are correct that SharpSerializer does not implement ignoring of property values when deserializing. This can be verified from the reference source for ObjectFactory.fillProperties(object obj, IEnumerable<Property> properties)
:
private void fillProperties(object obj, IEnumerable<Property> properties)
{
foreach (Property property in properties)
{
PropertyInfo propertyInfo = obj.GetType().GetProperty(property.Name);
if (propertyInfo == null) continue;
object value = CreateObject(property);
if (value == null) continue;
propertyInfo.SetValue(obj, value, _emptyObjectArray);
}
}
This code unconditionally sets any property read from the serialization stream into the incoming object using reflection, without checking the list of ignored attributes or properties.
Thus the only way to ignore your desired properties would seem to be to create your own versions of XmlPropertyDeserializer
or BinaryPropertyDeserializer
that skip or filter the unwanted properties. The following is one possible implementation for XML. This implementation reads the properties from XML into a Property
hierarchy as usual, then applies a filter action to remove properties corresponding to .NET properties with a custom attribute [SharpSerializerIgnoreForDeserialize]
applied, then finally creates the object tree using the pruned Property
.
[System.AttributeUsage(System.AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class SharpSerializerIgnoreForDeserializeAttribute : System.Attribute { }
public class PropertyDeserializerDecorator : IPropertyDeserializer
{
readonly IPropertyDeserializer deserializer;
public PropertyDeserializerDecorator(IPropertyDeserializer deserializer) => this.deserializer = deserializer ?? throw new ArgumentNullException();
public virtual void Open(Stream stream) => deserializer.Open(stream);
public virtual Property Deserialize() => deserializer.Deserialize();
public virtual void Close() => deserializer.Close();
}
public class CustomPropertyDeserializer : PropertyDeserializerDecorator
{
Action<Property> deserializePropertyAction;
public CustomPropertyDeserializer(IPropertyDeserializer deserializer, Action<Property> deserializePropertyAction = default) : base(deserializer) => this.deserializePropertyAction = deserializePropertyAction;
public override Property Deserialize()
{
var property = base.Deserialize();
if (deserializePropertyAction != null)
property.WalkProperties(p => deserializePropertyAction(p));
return property;
}
}
public static partial class SharpSerializerExtensions
{
public static SharpSerializer Create(SharpSerializerXmlSettings settings, Action<Property> deserializePropertyAction = default)
{
// Adapted from https://github.com/polenter/SharpSerializer/blob/42f9a20b3934a7f2cece356cc8116a861cec0b91/SharpSerializer/SharpSerializer.cs#L139
// By https://github.com/polenter
var typeNameConverter = settings.AdvancedSettings.TypeNameConverter ??
new TypeNameConverter(
settings.IncludeAssemblyVersionInTypeName,
settings.IncludeCultureInTypeName,
settings.IncludePublicKeyTokenInTypeName);
// SimpleValueConverter
var simpleValueConverter = settings.AdvancedSettings.SimpleValueConverter ?? new SimpleValueConverter(settings.Culture, typeNameConverter);
// XmlWriterSettings
var xmlWriterSettings = new XmlWriterSettings
{
Encoding = settings.Encoding,
Indent = true,
OmitXmlDeclaration = true,
};
// XmlReaderSettings
var xmlReaderSettings = new XmlReaderSettings
{
IgnoreComments = true,
IgnoreWhitespace = true,
};
// Create Serializer and Deserializer
var reader = new DefaultXmlReader(typeNameConverter, simpleValueConverter, xmlReaderSettings);
var writer = new DefaultXmlWriter(typeNameConverter, simpleValueConverter, xmlWriterSettings);
var _serializer = new XmlPropertySerializer(writer);
var _deserializer = new CustomPropertyDeserializer(new XmlPropertyDeserializer(reader), deserializePropertyAction);
var serializer = new SharpSerializer(_serializer, _deserializer)
{
//InstanceCreator = settings.InstanceCreator ?? new DefaultInstanceCreator(), -- InstanceCreator not present in SharpSerializer 3.0.1
RootName = settings.AdvancedSettings.RootName,
};
serializer.PropertyProvider.PropertiesToIgnore = settings.AdvancedSettings.PropertiesToIgnore;
serializer.PropertyProvider.AttributesToIgnore = settings.AdvancedSettings.AttributesToIgnore;
return serializer;
}
public static void WalkProperties(this Property property, Action<Property> action)
{
if (action == null || property == null)
throw new ArgumentNullException();
// Avoid cyclic dependencies.
// Reference.IsProcessed is true only for the first reference of an object.
bool skipProperty = property is ReferenceTargetProperty refTarget
&& refTarget.Reference != null
&& !refTarget.Reference.IsProcessed;
if (skipProperty) return;
action(property);
switch (property.Art)
{
case PropertyArt.Collection:
{
foreach (var item in ((CollectionProperty)property).Items)
item.WalkProperties(action);
}
break;
case PropertyArt.Complex:
{
foreach (var item in ((ComplexProperty)property).Properties)
item.WalkProperties(action);
}
break;
case PropertyArt.Dictionary:
{
foreach (var item in ((DictionaryProperty)property).Items)
{
item.Key.WalkProperties(action);
item.Value.WalkProperties(action);
}
}
break;
case PropertyArt.MultiDimensionalArray:
{
foreach (var item in ((MultiDimensionalArrayProperty )property).Items)
item.Value.WalkProperties(action);
}
break;
case PropertyArt.Null:
case PropertyArt.Simple:
case PropertyArt.Reference:
break;
case PropertyArt.SingleDimensionalArray:
{
foreach (var item in ((SingleDimensionalArrayProperty)property).Items)
item.WalkProperties(action);
}
break;
default:
throw new NotImplementedException(property.Art.ToString());
}
}
public static void RemoveIgnoredChildProperties(Property p)
{
if (p.Art == PropertyArt.Complex)
{
var items = ((ComplexProperty)p).Properties;
for (int i = items.Count - 1; i >= 0; i--)
{
if (p.Type.GetProperty(items[i].Name)?.IsDefined(typeof(SharpSerializerIgnoreForDeserializeAttribute), true) == true)
{
items.RemoveAt(i);
}
}
}
}
}
Then, given the following models:
public class Root
{
public List<Model> Models { get; set; } = new ();
}
public class Model
{
public string Value { get; set; }
[SharpSerializerIgnoreForDeserialize]
public string IgnoreMe { get; set; }
}
You would deserialize using the customized XmlPropertyDeserializer
as follows:
var settings = new SharpSerializerXmlSettings();
var customSerialzier = SharpSerializerExtensions.Create(settings, SharpSerializerExtensions.RemoveIgnoredChildProperties);
var deserialized = (Root)customSerialzier.Deserialize(stream);
If you need binary deserialization, use the following factory method to create the serializer instead:
public static partial class SharpSerializerExtensions
{
public static SharpSerializer Create(SharpSerializerBinarySettings settings, Action<Property> deserializePropertyAction = default)
{
// Adapted from https://github.com/polenter/SharpSerializer/blob/42f9a20b3934a7f2cece356cc8116a861cec0b91/SharpSerializer/SharpSerializer.cs#L168
// By https://github.com/polenter
var typeNameConverter = settings.AdvancedSettings.TypeNameConverter ??
new TypeNameConverter(
settings.IncludeAssemblyVersionInTypeName,
settings.IncludeCultureInTypeName,
settings.IncludePublicKeyTokenInTypeName);
// Create Serializer and Deserializer
Polenter.Serialization.Advanced.Binary.IBinaryReader reader;
Polenter.Serialization.Advanced.Binary.IBinaryWriter writer;
if (settings.Mode == BinarySerializationMode.Burst)
{
// Burst mode
writer = new BurstBinaryWriter(typeNameConverter, settings.Encoding);
reader = new BurstBinaryReader(typeNameConverter, settings.Encoding);
}
else
{
// Size optimized mode
writer = new SizeOptimizedBinaryWriter(typeNameConverter, settings.Encoding);
reader = new SizeOptimizedBinaryReader(typeNameConverter, settings.Encoding);
}
var _serializer = new BinaryPropertySerializer(writer);
var _deserializer = new CustomPropertyDeserializer(new BinaryPropertyDeserializer(reader), deserializePropertyAction);
var serializer = new SharpSerializer(_serializer, _deserializer)
{
//InstanceCreator = settings.InstanceCreator ?? new DefaultInstanceCreator(), -- InstanceCreator not present in SharpSerializer 3.0.1
RootName = settings.AdvancedSettings.RootName,
};
serializer.PropertyProvider.PropertiesToIgnore = settings.AdvancedSettings.PropertiesToIgnore;
serializer.PropertyProvider.AttributesToIgnore = settings.AdvancedSettings.AttributesToIgnore;
return serializer;
}
}
And do:
var settings = new SharpSerializerBinarySettings();
var customSerialzier = SharpSerializerExtensions.Create(settings, SharpSerializerExtensions.RemoveIgnoredChildProperties);
var deserialized = (Root)customSerialzier.Deserialize(stream);
Notes:
Demo fiddle #1 here for XML, and #2 here for binary.