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
Enable serialization IEnumerable<T> and IReadOnlyDictionary<T> descendants that have constructor with relevant collection #1187
Enable serialization IEnumerable<T> and IReadOnlyDictionary<T> descendants that have constructor with relevant collection #1187
Conversation
…dants that have constructor with relevant collection
Can anyone review this, or reject if the idea is weird? |
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 looks good. I am a bit concerned because a class that happens to implement a collection interface may not be simply a collection, but it is in the last checks of the dynamic resolver, so risk of regression seems minimal.
{ | ||
ParameterInfo[] parameters = constructor.GetParameters(); | ||
if (parameters.Length == 1 && | ||
allowedParameterTypes.Any(allowedType => allowedType.IsAssignableFrom(parameters[0].ParameterType))) |
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.
I think you have the IsAssignableFrom
backwards. If the ctor allowed MyCustomDictionary
, then IDictionary<K,V>
may be assignable from it, but ultimately our Activator.CreateInstance
call would fail because our Dictionary<K,V>
object cannot be assigned to MyCustomDictionary
If you swap it to be:
if (parameters.Length == 1 && parameters[0].ParameterType.IsAssignableFrom(typeof(Dictionary<,>).MakeGenericType(keyType, valueType))
Then we know definitively that the ultimate invocation should succeed, and all the 3 types you were previously checking individually will all just work.
foreach (var constructor in ti.DeclaredConstructors) | ||
{ | ||
var parameters = constructor.GetParameters(); | ||
if (parameters.Length == 1 && paramInterface.IsAssignableFrom(parameters[0].ParameterType)) |
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.
Same here: it's backwards.
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. Although detecting IEnumerable<T>
in an arbitrary object could lead to false matches, also matching on the constructor signature as you're doing seems like it will lead to a high match. And if it ever misses, the user can always specify the formatter to use.
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.
Thank you, I think it's good.
Is your feature request related to a problem? Please describe.
I have heavy usage of
IReadOnlyCollection
andIReadOnlyDictionary
descendants in my code and confused, why I can serialize(IReadOnlyCollection<int>)myCollection
, but can't serializemyCollection
itself? And also I can't deserialize some collections, because they doesn't haveICollection<T>
interface (which is overengineered).Describe the solution you'd like.
I think, that collections that have constructor with parameter of
IEnumerable<T>
or its descendants must be serialized/deserialized from out the box. Also anyIReadOnlyDictionary
object having constructor with parameter ofIDictionary
/IReadOnlyDictionary
must be supported.Describe alternatives you've considered
I can write formatters for each collection, but that's has some issues: