Kenneth Ry Ulrik created AVRO-4318:
--------------------------------------

             Summary: C# AvroGen: Marker Interface for Avro Unions
                 Key: AVRO-4318
                 URL: https://issues.apache.org/jira/browse/AVRO-4318
             Project: Apache Avro
          Issue Type: Improvement
          Components: csharp
    Affects Versions: 1.12.1
            Reporter: Kenneth Ry Ulrik


Currently, if a field in an Avro record defines an Avro Union of types, the 
resulting C# class property type becomes "object", leaving 

*Sample schema:*

 
{code:java}
{
  "name": "RecordWithAvroUnionField",
  "namespace": "example",
  "type": "record", 
  "fields": [
    {
      "name": "avroUnionField",
      "type": [
        {
          "name": "AvroUnionTypeA",
          "type": "record",
          "fields": [
            {
              "name": "myString",
              "type": "string"
            }
          ]
        },
        {
          "name": "AvroUnionTypeB",
          "type": "record",
          "fields": [
            {
              "name": "myInt",
              "type": "int"
            }
          ]
        }
      ]
    }
  ]
}{code}
*What gets generated today:*
 * RecordWithAvroUnionField.cs
 * AvroUnionTypeA.cs
 * AvroUnionTypeB.cs

+What's wrong with it?+
 * The "avroUnionField" field is generated as a property with type "object"
 * Despite RecordWithAvroUnionField literally containing and declaring the 
types AvroUnionTypeA and AvroUnionTypeB, there is no type system reference, 
direct or otherwise, to them at all, so it's up to consumers to "guess" / 
explicitly cast into types that they must in advance know can be in this 
"object"-typed property.

+Excerpt of generated "avroUnionField" C# property:+

(generates "object" property, requiring manual "guessing" / manual type-casting 
to explicitly known types )

 
{code:java}
public object avroUnionField
{
    get
    {
        return this._avroUnionField;
    }
    set
    {
        this._avroUnionField = value;
    }
}{code}
+Excerpt of generated "AvroUnionTypeA" type as an example:+

(has no type system correlation to RecordWithAvroUnionField in any way)

 
{code:java}
public partial class AvroUnionTypeA : global::Avro.Specific.ISpecificRecord
{ ... } {code}
 

 

*The proposal for what to generate instead:*
 * A marker (empty) interface, distinctly defined and named according to the 
type and field name
 * For each type declared as part of an Avro union, add the marker interface 
onto the generated class.
 * Modify Avro Union fields to use their distinctly defined marker interface as 
the property type instead of object

+Marker interface naming proposal:+

(ensures uniqueness, avoiding rare scenarios where multiple nested types 
declared in Avro Unions may declare a field with the same name, both of which 
declare an Avro Union)

Format: $"\{NameOfTypeContainingAvroUnionField}_\{AvroUnionFieldName}"

 
{code:java}
public interface IRecordWithAvroUnionField_avroUnionField { }{code}
 

+"AvroUnionTypeA" type example:+

(implements the marker interface, because it is declared as part of this 
particular Avro Union)

 
{code:java}
public partial class AvroUnionTypeA : global::Avro.Specific.ISpecificRecord, 
IRecordWithAvroUnionField_avroUnionField
{ ... }  {code}
 

+"avroUnionField" C# property in the "RecordWithAvroUnionField" class:+

(uses the marker interface as the type of the Avro Union field)

 
{code:java}
public IRecordWithAvroUnionField_avroUnionField avroUnionField
{
    get
    {
        return this._avroUnionField;
    }
    set
    {
        this._avroUnionField = value;
    }
}{code}
 

 

*Future note for C# union types:*

With C# 15 and .NET 11, with the introduction of union types, one could instead 
generate a union type definition, with each class generated for the Avro Union 
types being declared as part of that union type, allowing the C# compiler to 
further aid developers by ensuring complete handling of all union member-type 
possibilities in code that deserializes to the generated class.

[Explore union types in C# 15 - .NET 
Blog|https://devblogs.microsoft.com/dotnet/csharp-15-union-types/]

I.e.:
{code:java}
public union RecordWithAvroUnionField_avroUnionField(AvroUnionTypeA, 
AvroUnionTypeB); {code}
 

 



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to