dotnet / dotnet/runtime

[API Proposal]: Handle union as a xsd:choice in XmlSerializer as a type safe exhaustive alternative

Open
#132,162 0 comments 0 reactions 0 assignees View on GitHub
api-suggestion area-Serialization untriaged
Dominant language
C#
Stars
18.3k
Forks
5.6k
PR merge metrics
PR metrics pending

Description

### Background and motivation

*I apologize if I used wrong issue template but I believe the only other is a blank one which isn't any better for this proposal.*

With C# 15 and .NET 11 bringing union types I think now's a good time to propose a type-safe xsd:choice and XmlSerializer.

Currently, for this schema:

```xsd




















```

and an instance document that has to pick exactly one of the two:

```xml


4

```

To consume that Drawing class today, XmlSerializer needs Outline typed as `object` with stacked XmlElementAttributes:

```cs
public class Drawing
{
[XmlElement("Circle", typeof(Circle))]
[XmlElement("Rectangle", typeof(Rectangle))]
public object Outline { get; set; }
}
```

That schema is a closed, type-safe constraint — Outline is either Circle or Rectangle and nothing else. But in C# it can't be said the same. `object` accepts anything. The choice between Circle and Rectangle is not enforced and it's up to consumers of this class to make sure they provided the right types.

The situation is even worse for repeated choice:

```xsd






```

```xml

4
23
1

```

For XmlSerializer to be able to deserialize Xml files described with such schema a new property for Drawing needs to be introduced:

```cs
public class Drawing
{
[XmlElement("Circle", typeof(Circle))]
[XmlElement("Rectangle", typeof(Rectangle))]
[XmlChoiceIdentifier(nameof(ShapesElementName))]
public object[] Shapes;

[XmlIgnore]
public ShapeChoice[] ShapesElementName;
}

public enum ShapeChoice { Circle, Rectangle }
```

This isn't type safe nor intuitive. And that's not all. Not only that another property `ShapesElementName` is there *only* for XmlSerializer but also a *new mandatory* enum with value names that **have to match** element names has to be defined.

### API Proposal

So my proposal is simple:

No surface API change whatsoever. The only change would be in XmlSerializer's deserialization/serialization behavior. A type safe, intuitive and exhaustive alternative.

Instead of `object` or `object[]` XmlSerializer would use unions to enforce type safety. See below in API Usage.

To be clear I do not propose a complete overhaul change of xsd:choice. Keep the old XmlChoiceIdentifier and add new functionality to the existing API.

### API Usage

So with unions the structure would look like this:

```cs
public union Outline(Circle, Rectangle);

public class Drawing
{
[XmlElement]
public Outline Outline;
}
```

or with an array:

```cs
public union Shape(Circle, Rectangle);

public class Drawing
{
[XmlArray]
public Shape[] Shapes;
}
```

Serializing and deserializing would not need to change on the API level:

```cs
XmlSerializer serializer = new(typeof(Drawing));
Drawing? drawing = (Drawing?)serializer.Deserialize(File.OpenRead("drawings.xml"));
```

### Alternative Designs

Maybe a new attribute that would decorate a union which would tell XmlSerializer that it's a choice might be needed. I do not see that deep into .NET runtime:

```cs
[XmlChoice]
public union Outline(Circle, Rectangle);
```

### Risks

Currently none since unions are in preview.

But if not implemented in the upcoming .NET 11 and rather in later versions some breaking changes might arise.

Hopefully this will get resolve before that but by looking on the amount of open issues I can only have hopes.

Contributor guide

Open the contributing guide

Research direction

The proposal targets XmlSerializer serialization and deserialization of xsd:choice, using the Drawing, Outline, and Shape examples and the existing XmlChoiceIdentifier API. Start by reviewing how XmlSerializer currently handles these choice members. Done would require a feasible design for union-based handling without a surface API change, along with defined serialization and deserialization behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
api, backend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.