-
-
Notifications
You must be signed in to change notification settings - Fork 482
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OmitDefaults doesn't work for properties of sub-objects #840
Comments
it seems to work if there are no objects inside that sub-object without defaults. I'm still not sure the exact scenarios this is and is-not working in |
I haven’t looked to closely at this yet. But. According to this class/code in order to not output PropOfA you would need to set DefaultValue(null) on it. The way you have your defaultvalue on the integer I would have assumed would work based on the below code. I’ll take a closer look maybe today. YamlDotNet/YamlDotNet/Serialization/ObjectGraphVisitors/DefaultValuesObjectGraphVisitor.cs Line 80 in a6845eb
|
I do feel there is a bug in there since defaults of an instance type is always null. So that should probably be taken into account in that class. |
So there's no way to omit a non-null default for a YAML sub-category or Array? |
On an instance type you would need to add the defaultvalue of null attribute like you have commented out. I think. I haven’t tested or played with that. I was hoping to have time over the weekend but that didn’t happen. |
Arrays are insurance type. So defaults of that would be null. But you couldn’t do an empty array as a default. If that makes sense. |
Right, so you're confirming that only primitives can have non-null defaults ( and there's no way to say "this is a static-readonly value I consider default for you to omit"). Okay. That's dissapointing. |
Ok. Got to spend about 5 minutes. You might. And I strongly emphasize might. Be able to create a custom System.ComponentModel.TypeDescriptionProvider. Register it with System.ComponentModel.TypeConverter.AddProvider. Then when you specify the DefaultValue attribute put the type and probably and empty string. You will also need to create an Equals override method on your class. Then you could do all sorts of things. No guarantees that it will work though. |
Figured it out for you using TypeConverters and no changes necessary to the var instanceOfA = new ExampleA(); // leaving the defaults
var text = new SerializerBuilder()
.ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitDefaults)
.Build()
.Serialize(instanceOfA);
Console.WriteLine(text);
Console.ReadLine();
public class ExampleBTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
if (string.IsNullOrEmpty(value as string))
{
// Default value to check against
return new ExampleB { PropOfB = 3 };
}
return null;
}
}
[TypeConverter(typeof(ExampleBTypeConverter))]
public class ExampleB
{
public ExampleB() { }
public int PropOfB { get; set; } = 3;
public override bool Equals(object? obj)
{
return (obj as ExampleB)?.PropOfB == PropOfB;
}
}
public class ExampleA
{
public ExampleA() { }
[DefaultValue(typeof(ExampleB), null)]
public ExampleB PropOfA { get; set; } = new();
} |
If you want to exclude var instanceOfA = new ExampleA(); // leaving the defaults
var text = new SerializerBuilder()
.ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitDefaults)
.Build()
.Serialize(instanceOfA);
Console.WriteLine(text);
Console.ReadLine();
public class ExampleB
{
public ExampleB() { }
[DefaultValue(3)]
public int PropOfB { get; set; } = 3;
public override bool Equals(object? obj)
{
return (obj as ExampleB)?.PropOfB == PropOfB;
}
}
public class ExampleA
{
public ExampleA() { }
public ExampleB PropOfA { get; set; } = new();
} |
It doesn't solve my issues with arrays, but it absolutely fixes the bug report as it's written. |
If you don't have to have it as an array, you could create another class inheriting Like this: var instanceOfA = new ExampleA
{
PropOfA = new ExampleBList
{
new ExampleB
{
PropOfB = 3
}
}
};
var text = new SerializerBuilder()
.ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitDefaults)
.Build()
.Serialize(instanceOfA);
Console.WriteLine(text);
Console.ReadLine();
public class ExampleB
{
public ExampleB() { }
public int PropOfB { get; set; }
public override bool Equals(object? obj)
{
return (obj as ExampleB)?.PropOfB == PropOfB;
}
}
public class ExampleA
{
public ExampleA() { }
[DefaultValue(typeof(ExampleBList), null)]
public ExampleBList PropOfA { get; set; }
}
public class ExampleBListTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
if (string.IsNullOrEmpty(value as string))
{
return new ExampleBList
{
new ExampleB()
{
PropOfB = 3
}
};
}
return null;
}
}
[TypeConverter(typeof(ExampleBListTypeConverter))]
public class ExampleBList : List<ExampleB>
{
public override bool Equals(object? obj)
{
var list = obj as IEnumerable<ExampleB>;
if (list != null)
{
if (this.Count == list.Count())
{
foreach (var item in this)
{
//make sure each item in the incoming list only exists once in this list
if (list.Where(x => x.Equals(item)).Count() != 1)
{
return false;
}
}
return true;
}
}
return false;
}
} |
If you need to have it exposed as an array, you can do something like this with the var instanceOfA = new ExampleA
{
PropOfA = new []
{
new ExampleB
{
PropOfB = 3
}
}
};
var text = new SerializerBuilder()
.ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitDefaults)
.Build()
.Serialize(instanceOfA);
Console.WriteLine(text);
Console.ReadLine();
public class ExampleB
{
public ExampleB() { }
public int PropOfB { get; set; }
public override bool Equals(object? obj)
{
return (obj as ExampleB)?.PropOfB == PropOfB;
}
}
public class ExampleA
{
public ExampleA() { }
[DefaultValue(typeof(ExampleBList), null)]
[YamlMember(Alias = "PropOfA")]
public ExampleBList PropOfADefaulted { get; set; }
[YamlIgnore]
public ExampleB[] PropOfA
{
get
{
return PropOfADefaulted.ToArray();
}
set
{
PropOfADefaulted = new ExampleBList(value);
}
}
}
public class ExampleBListTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
if (string.IsNullOrEmpty(value as string))
{
return new ExampleBList
{
new ExampleB()
{
PropOfB = 3
}
};
}
return null;
}
}
[TypeConverter(typeof(ExampleBListTypeConverter))]
public class ExampleBList : List<ExampleB>
{
public ExampleBList() { }
public ExampleBList(IEnumerable<ExampleB> collection) : base(collection) { }
public override bool Equals(object? obj)
{
var list = obj as IEnumerable<ExampleB>;
if (list != null)
{
if (this.Count == list.Count())
{
foreach (var item in this)
{
//make sure each item in the incoming list only exists once in this list
if (list.Where(x => x.Equals(item)).Count() != 1)
{
return false;
}
}
return true;
}
}
return false;
}
} |
Thank you very much. No my secondary problem was with having a default value for a primitive array like |
Describe the bug
When using "DefaultValuesHandling.OmitDefaults", I would expect serializing an object with an object inside to omit defaults of that sub-object.
To Reproduce
The text was updated successfully, but these errors were encountered: