Skip to content
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

[Question] deserialization of immutable collection #551

Open
aPlacuzzi opened this issue Dec 15, 2020 · 4 comments
Open

[Question] deserialization of immutable collection #551

aPlacuzzi opened this issue Dec 15, 2020 · 4 comments

Comments

@aPlacuzzi
Copy link

Hi all,

With C#8 they introduce immutable collections like ImmutableList, ImmutableDictionary, and go on.

The deserialization of these collections seems to be actually not supported.

What is the best way to add this extension to the deserializer?

@NiccoMlt
Copy link

Same problem here

@aPlacuzzi
Copy link
Author

I'm already here, but with a solution (or at least a workaround) for ImmutableList.
I took inspiration from CollectionNodeDeserializer.

/// <summary>
/// Node deserializer to deserialize <see cref="IImmutableList{T}"/>.
/// </summary>
internal class ImmutableListNodeDeserializer : INodeDeserializer
{
	/// <inheritdoc/>
	public bool Deserialize(IParser reader, Type expectedType, Func<IParser, Type, object> nestedObjectDeserializer, out object value)
	{
		if (!(expectedType.IsInterface && expectedType.IsGenericType && expectedType.GetGenericTypeDefinition() == typeof(IImmutableList<>)))
		{
			value = null;
			return false;
		}
		const string methodName = "AddRange";
		var itemType = expectedType.GetGenericArguments()[0];
		var list = (Activator.CreateInstance(typeof(List<>).MakeGenericType(itemType)) as IList;
		if (list == null)
		{
			value = null;
			return false;
		}
		DeserializeHelper(itemType, reader, nestedObjectDeserializer, list, canUpdate: true);
		value = Activator.CreateInstance(typeof(ImmutableList<>).MakeGenericType(itemType), true);
		value = value.GetType()
			.GetMethod(methodName)
			.Invoke(value, new[] { list });
		return true;
	}

	private static void DeserializeHelper(Type tItem, IParser parser, Func<IParser, Type, object> nestedDeserializer, IList result, bool canUpdate)
	{
		parser.Consume<SequenceStart>();
		while (!parser.TryConsume<SequenceEnd>(out var _))
		{
			var current = parser.Current;

			var value = nestedDeserializer(parser, tItem);
			if (value is IValuePromise promise)
			{
				if (canUpdate)
				{
					var index = result.Add(tItem.GetTypeInfo().IsValueType ? Activator.CreateInstance(tItem) : null);
					promise.ValueAvailable += v => result[index] = TypeConverter.ChangeType(v, tItem, CultureInfo.InvariantCulture);
				}
				else
				{
					throw new ForwardAnchorNotSupportedException(
						current?.Start ?? Mark.Empty,
						current?.End ?? Mark.Empty,
						"Forward alias references are not allowed because this type does not implement IList<>");
				}
			}
			else
			{
				result.Add(TypeConverter.ChangeType(value, tItem, CultureInfo.InvariantCulture));
			}
		}
	}
}

@somegenericdev
Copy link

Any updates on this? This is something it would be really nice to have.

@EdwardCooke
Copy link
Collaborator

We don't have it built in, we welcome PR's though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants