-
Notifications
You must be signed in to change notification settings - Fork 383
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
Modified serilization to support units saved as IComparable #200
Modified serilization to support units saved as IComparable #200
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an interesting idea and I can understand why this would be convenient. I am a little concerned we are putting too much magic in the serializer though, but I'm not too familiar with what are common practices in custom serializers and json.net. I personally would be a little afraid to rely on the type names for serialization, due to possible future breaking changes out of my control and how to deal with that, but I suppose that is up to the application to decide.
If I understand correctly, one must explicitly enable TypeNameHandling.Object/All/Auto
both when serializing and deserializing in order for this to work, and then it "just works".
- Can you extract the serializer setup code so that it is more clear that the test cases share identical serializer and deserializer settings?
- Is there a reason for not using
TypeNameHandling.Auto
in both serialization and deserialization? From the docs it seems a reasonable one to use. - Could you add a test case where you serialize an object with three properties, of the same types you use in the existing cases?
- Could you add a test case with a non-UnitsNet type implementing IComparable, that also has
Unit
andValue
properties?
objectType == typeof(ValueUnit) || | ||
// All unit types implement IComparable | ||
objectType==typeof(IComparable) || | ||
objectType.FullName.StartsWith("System." + nameof(IComparable))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this string comparison required, doesn't the typeof check cover all cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was very much trial and error and a later refactoring made this unnecessary.
I've extracted the serializer code. Let me know if it is clear enough. After refactoring my tests I realized that I didn't need Added the requested test cases, trying all different combinations with 3 Added the non UnitsNet Also added some |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Starting to look good, a couple of things still.
} | ||
} | ||
|
||
private static JsonSerializerSettings CreateJsonSerializerSettigns() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo
Assert.That(deserializedTestObject.Unit, Is.EqualTo("Test")); | ||
} | ||
|
||
[Test, TestCaseSource(nameof(TestObjectsForThreeObjectsInIComparableWithDifferentValues_ExpectAllCorrectlyDeserialized))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This part was slightly confusing to me, as I haven't used TestCaseSource before. If there is only one case, I think I would prefer a normal method that give me that TestObjWithThreeIComparable
object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will actually be 27 tests (testing all combinations of objects). Might be a little too much. I started with 3 very similar tests and did this to reduce code duplication and then it was easy to add the loop with all combinations. I have to admit that I don't fully understand the serialization so I rather have some extra tests just to be sure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, ok. 27 tests seem a bit overboard, yes. Tests are nice, but I want each test to bring value and from the way I understand the implementation design and the test, I don't see how testing multiple variations of TestObjWithThreeIComparable
will help us avoid bugs here. I think I'd rather have one or possibly two test cases with different combinations, but that should be quite enough, I think.
Their docs helped me understand what goes on: http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_TypeNameHandling.htm
Basically they add a $type
prop that describes the actual object type when it was serialized, then the deserializer tries to use the exact same type by its assembly name, and full type name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, wrong link: http://www.newtonsoft.com/json/help/html/serializetypenamehandling.htm
var deserializedTestObject = JsonConvert.DeserializeObject<TestObjWithThreeIComparable>(json, jsonSerializerSettings); | ||
|
||
Assert.That(deserializedTestObject.Value1.GetType(), Is.EqualTo(comparable1.GetType())); | ||
Assert.That(((deserializedTestObject.Value1)), Is.EqualTo(comparable1)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Redundant parantheses.
Assert.That(((deserializedTestObject.Value3)), Is.EqualTo(comparable3)); | ||
} | ||
|
||
public static object[] TestObjectsForThreeObjectsInIComparableWithDifferentValues_ExpectAllCorrectlyDeserialized |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be private.
} | ||
|
||
internal class TestObj | ||
{ | ||
public Frequency? NullableFrequency { get; set; } | ||
public Frequency NonNullableFrequency { get; set; } | ||
} | ||
|
||
internal class TestObjWithValueAndUnit : IComparable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All these types can be private, can't they?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's true. Followed the existing class, will change all of them.
}; | ||
JsonSerializerSettings jsonSerializerSettings = CreateJsonSerializerSettigns(); | ||
|
||
string json = JsonConvert.SerializeObject(testObjWithIComparable,jsonSerializerSettings); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add space between params.
Fixed the typos and formatting. Kept the TestCaseSource. Let's discuss further. |
Will try to get to this tomorrow. On Tue, Nov 1, 2016, 10:39 Erik Ovegård notifications@github.com wrote:
|
I removed the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me. I think this is ready for a new alpha nuget. Serialization is still kind of experimental, represented by the prerelease nuget.
Nuget 1.0.0-alpha5 is now out. |
I had a class that I needed to serialize that had a unit as a IComparable. This pull requests makes this possible. I've tried testing other alternatives to not break anything. Let me know if you can think of any other use cases that should be tested.