-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Add support for collection types with parameterless or IEnumerable<T> constructors. #80688
Comments
Tagging subscribers to this area: @dotnet/area-system-collections Issue DetailsWe are migrating our code base from Newtonsoft to System.Text.Json. While testing this migration effort, we have encountered the following error while deserializing a type which uses ConcurrentBag I see that this also documented here - https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/supported-collection-types?pivots=dotnet-7-0#systemcollectionsconcurrent-namespace Is there any workaround for providing support for ConcurrentBag type? This is a major blocker in our migration effort as all hot path scenarios are dependent on this type
|
you want a custom JsonConverter for your |
Here's a simple way to write a custom converter for ConcurrentBag: public class ConcurrentBagConverter<T> : JsonConverter<ConcurrentBag<T>>
{
private readonly JsonConverter<IEnumerable<T>> _enumerableConverter = (JsonConverter<IEnumerable<T>>)JsonSerializerOptions.Default.GetConverter(typeof(IEnumerable<T>));
public override ConcurrentBag<T>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
IEnumerable<T>? result = _enumerableConverter.Read(ref reader, typeToConvert, options);
return result is null ? null : new ConcurrentBag<T>(result);
}
public override void Write(Utf8JsonWriter writer, ConcurrentBag<T> value, JsonSerializerOptions options)
=> _enumerableConverter.Write(writer, value, options);
} In the future we should add support for collection types that satisfy common conventions such as
Related to #71944. |
@eiriktsarpalis thanks for sharing the sample,
|
@snjosephms that should work fine since we're not using same type for serialization/deserialization as in your case. if we change your Serialize call to pass in IEnumerable type that should not require extra options as well |
@eiriktsarpalis How would you go about registering your ConcurrentBagConverter? I'm having trouble with the syntax, because it expects a generic type to be passed in, when we would want to use this converter for all usages of ConcurrentBag, regardless of the generic type. EDIT: For others who find this thread, the answer was to create a factory class that can be added to the options Converters list:
|
@justintoth I would probably simplify this to the following, full code: var options = new JsonSerializerOptions { Converters = { new ConcurrentBagConverter() } };
var bag = JsonSerializer.Deserialize<ConcurrentBag<int>>("[1, 2, 3]", options);
Console.WriteLine(bag.Count);
public class ConcurrentBagConverter<T> : JsonConverter<ConcurrentBag<T>>
{
private readonly JsonConverter<IEnumerable<T>> _enumerableConverter;
public ConcurrentBagConverter(JsonConverter<IEnumerable<T>> enumerableConverter)
=> _enumerableConverter = enumerableConverter;
public override ConcurrentBag<T>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
IEnumerable<T>? result = _enumerableConverter.Read(ref reader, typeof(IEnumerable<T>), options);
return result is null ? null : new ConcurrentBag<T>(result);
}
public override void Write(Utf8JsonWriter writer, ConcurrentBag<T> value, JsonSerializerOptions options)
=> _enumerableConverter.Write(writer, value, options);
}
public class ConcurrentBagConverter : JsonConverterFactory
{
public override bool CanConvert(Type typeToConvert) => typeToConvert.IsGenericType && typeToConvert.GetGenericTypeDefinition() == typeof(ConcurrentBag<>);
public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
Debug.Assert(CanConvert(typeToConvert));
Type elementType = typeToConvert.GetGenericArguments()[0];
Type ienumerableType = typeof(IEnumerable<>).MakeGenericType(elementType);
Type converterType = typeof(ConcurrentBagConverter<>).MakeGenericType(elementType);
JsonConverter ienumerableConverter = options.GetConverter(ienumerableType);
return (JsonConverter)Activator.CreateInstance(converterType, ienumerableConverter)!;
}
} |
Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis |
We are migrating our code base from Newtonsoft to System.Text.Json.
While testing this migration effort, we have encountered the following error while deserializing a type which uses ConcurrentBag
type: "Message=The collection type 'System.Collections.Concurrent.ConcurrentBag`1' is abstract, an interface, or is read only, and could not be instantiated and populated."
I see that this also documented here - https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/supported-collection-types?pivots=dotnet-7-0#systemcollectionsconcurrent-namespace
Is there any workaround for providing support for ConcurrentBag type?
This is a major blocker in our migration effort as all hot path scenarios are dependent on this type
The text was updated successfully, but these errors were encountered: