From 632ae3d9752c0bcb800ecc5df50c4a15e381dc1b Mon Sep 17 00:00:00 2001 From: "karyna.bilotska" Date: Wed, 7 Aug 2024 12:50:04 +0200 Subject: [PATCH 1/3] AVRO-4028: [c#] handle nested dictionary type --- .../src/apache/main/Specific/ObjectCreator.cs | 186 +++++++++++------- .../test/Specific/ObjectCreatorTests.cs | 3 + 2 files changed, 120 insertions(+), 69 deletions(-) diff --git a/lang/csharp/src/apache/main/Specific/ObjectCreator.cs b/lang/csharp/src/apache/main/Specific/ObjectCreator.cs index 073b107958a..3d93dce241f 100644 --- a/lang/csharp/src/apache/main/Specific/ObjectCreator.cs +++ b/lang/csharp/src/apache/main/Specific/ObjectCreator.cs @@ -34,10 +34,15 @@ public sealed class ObjectCreator public static ObjectCreator Instance { get; } = new ObjectCreator(); /// - /// Static generic dictionary type used for creating new dictionary instances + /// Static generic dictionary type used for creating new Dictionary instances /// private readonly Type GenericMapType = typeof(Dictionary<,>); + /// + /// Static generic dictionary type used for creating new IDictionary instances + /// + private readonly Type GenericIMapType = typeof(IDictionary<,>); + /// /// Static generic list type used for creating new array instances /// @@ -90,6 +95,14 @@ private Type FindType(string name) return GenericIListType.MakeGenericType(FindType(itemTypeName)); } + if (TryGetIDictionaryItemTypeName(name, out var itemTypesName)) + { + var key = itemTypesName[0].GetType().Name; + var value = itemTypesName[1]; + + return GenericIMapType.MakeGenericType(FindType(key), FindType(value)); + } + if (TryGetNullableItemTypeName(name, out itemTypeName)) { return GenericNullableType.MakeGenericType(FindType(itemTypeName)); @@ -168,6 +181,40 @@ private bool TryGetIListItemTypeName(string name, out string itemTypeName) return false; } + private bool TryGetIDictionaryItemTypeName(string name, out string[] itemTypesName) + { + const string dictionaryPrefix = "IDictionary<"; + const string fullDictionaryPrefix = "System.Collections.Generic.IDictionary<"; + string[] separators = { ", ", "," }; + + if (!name.EndsWith(">", StringComparison.Ordinal)) + { + itemTypesName = null; + return false; + } + + if (name.StartsWith(fullDictionaryPrefix, StringComparison.Ordinal)) + { + itemTypesName = name + .Substring(dictionaryPrefix.Length, name.Length - dictionaryPrefix.Length - 1) + .Split(separators, 2, StringSplitOptions.None); + + return true; + } + + if (name.StartsWith(dictionaryPrefix, StringComparison.Ordinal)) + { + itemTypesName = name + .Substring(dictionaryPrefix.Length, name.Length - dictionaryPrefix.Length - 1) + .Split(separators, 2, StringSplitOptions.None); + + return true; + } + + itemTypesName = null; + return false; + } + private bool TryGetNullableItemTypeName(string name, out string itemTypeName) { const string nullablePrefix = "Nullable<"; @@ -201,87 +248,88 @@ private bool TryGetNullableItemTypeName(string name, out string itemTypeName) /// public Type GetType(Schema schema) { - switch(schema.Tag) { - case Schema.Type.Null: - break; - case Schema.Type.Boolean: - return typeof(bool); - case Schema.Type.Int: - return typeof(int); - case Schema.Type.Long: - return typeof(long); - case Schema.Type.Float: - return typeof(float); - case Schema.Type.Double: - return typeof(double); - case Schema.Type.Bytes: - return typeof(byte[]); - case Schema.Type.String: - return typeof(string); - case Schema.Type.Union: - { - if (schema is UnionSchema unSchema && unSchema.Count == 2) + switch (schema.Tag) + { + case Schema.Type.Null: + break; + case Schema.Type.Boolean: + return typeof(bool); + case Schema.Type.Int: + return typeof(int); + case Schema.Type.Long: + return typeof(long); + case Schema.Type.Float: + return typeof(float); + case Schema.Type.Double: + return typeof(double); + case Schema.Type.Bytes: + return typeof(byte[]); + case Schema.Type.String: + return typeof(string); + case Schema.Type.Union: { - Schema s1 = unSchema.Schemas[0]; - Schema s2 = unSchema.Schemas[1]; - - // Nullable ? - Type itemType = null; - if (s1.Tag == Schema.Type.Null) + if (schema is UnionSchema unSchema && unSchema.Count == 2) { - itemType = GetType(s2); - } - else if (s2.Tag == Schema.Type.Null) - { - itemType = GetType(s1); - } + Schema s1 = unSchema.Schemas[0]; + Schema s2 = unSchema.Schemas[1]; - if (itemType != null) - { - if (itemType.IsValueType && !itemType.IsEnum) + // Nullable ? + Type itemType = null; + if (s1.Tag == Schema.Type.Null) { - try - { - return GenericNullableType.MakeGenericType(itemType); - } - catch + itemType = GetType(s2); + } + else if (s2.Tag == Schema.Type.Null) + { + itemType = GetType(s1); + } + + if (itemType != null) + { + if (itemType.IsValueType && !itemType.IsEnum) { + try + { + return GenericNullableType.MakeGenericType(itemType); + } + catch + { + } } - } - return itemType; + return itemType; + } } - } - return typeof(object); - } - case Schema.Type.Array: - { - ArraySchema arrSchema = schema as ArraySchema; - Type itemSchema = GetType(arrSchema.ItemSchema); - - return GenericListType.MakeGenericType(itemSchema); - } - case Schema.Type.Map: - { - MapSchema mapSchema = schema as MapSchema; - Type itemSchema = GetType(mapSchema.ValueSchema); + return typeof(object); + } + case Schema.Type.Array: + { + ArraySchema arrSchema = schema as ArraySchema; + Type itemSchema = GetType(arrSchema.ItemSchema); - return GenericMapType.MakeGenericType(typeof(string), itemSchema ); - } - case Schema.Type.Enumeration: - case Schema.Type.Record: - case Schema.Type.Fixed: - case Schema.Type.Error: - { - // Should all be named types - if (schema is NamedSchema named) + return GenericListType.MakeGenericType(itemSchema); + } + case Schema.Type.Map: { - return FindType(named.Fullname); + MapSchema mapSchema = schema as MapSchema; + Type itemSchema = GetType(mapSchema.ValueSchema); + + return GenericMapType.MakeGenericType(typeof(string), itemSchema); } + case Schema.Type.Enumeration: + case Schema.Type.Record: + case Schema.Type.Fixed: + case Schema.Type.Error: + { + // Should all be named types + if (schema is NamedSchema named) + { + return FindType(named.Fullname); + } - break; - } + break; + } } // Fallback diff --git a/lang/csharp/src/apache/test/Specific/ObjectCreatorTests.cs b/lang/csharp/src/apache/test/Specific/ObjectCreatorTests.cs index d6b29d5d954..da3f606660a 100644 --- a/lang/csharp/src/apache/test/Specific/ObjectCreatorTests.cs +++ b/lang/csharp/src/apache/test/Specific/ObjectCreatorTests.cs @@ -76,6 +76,9 @@ public void TestGetTypeEquals(string name, Schema.Type schemaType, Type expected [TestCase("IList>>", Schema.Type.Array, typeof(IList>>>))] [TestCase("System.Collections.Generic.IList>>", Schema.Type.Array, typeof(IList>>>))] [TestCase("Foo", Schema.Type.Map, typeof(IDictionary))] + [TestCase("IDictionary", Schema.Type.Map, typeof(IDictionary>))] + [TestCase("IDictionary>>", Schema.Type.Map, typeof(IDictionary>>>))] + [TestCase("System.Collections.Generic.IDictionary>>", Schema.Type.Map, typeof(IDictionary>>>))] [TestCase("Nullable", Schema.Type.Array, typeof(IList>))] [TestCase("System.Nullable", Schema.Type.Array, typeof(IList))] [TestCase("IList>", Schema.Type.Array, typeof(IList>))] From 87db8dcd7934c371282fb0405a9d2a5f60c73df2 Mon Sep 17 00:00:00 2001 From: "karyna.bilotska" Date: Thu, 15 Aug 2024 18:33:46 +0200 Subject: [PATCH 2/3] AVRO-4028: remove formatting changes --- .../src/apache/main/Specific/ObjectCreator.cs | 67 +++++++++---------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/lang/csharp/src/apache/main/Specific/ObjectCreator.cs b/lang/csharp/src/apache/main/Specific/ObjectCreator.cs index 3d93dce241f..5312c01df14 100644 --- a/lang/csharp/src/apache/main/Specific/ObjectCreator.cs +++ b/lang/csharp/src/apache/main/Specific/ObjectCreator.cs @@ -248,43 +248,42 @@ private bool TryGetNullableItemTypeName(string name, out string itemTypeName) /// public Type GetType(Schema schema) { - switch (schema.Tag) - { - case Schema.Type.Null: - break; - case Schema.Type.Boolean: - return typeof(bool); - case Schema.Type.Int: - return typeof(int); - case Schema.Type.Long: - return typeof(long); - case Schema.Type.Float: - return typeof(float); - case Schema.Type.Double: - return typeof(double); - case Schema.Type.Bytes: - return typeof(byte[]); - case Schema.Type.String: - return typeof(string); - case Schema.Type.Union: + switch (schema.Tag) { + case Schema.Type.Null: + break; + case Schema.Type.Boolean: + return typeof(bool); + case Schema.Type.Int: + return typeof(int); + case Schema.Type.Long: + return typeof(long); + case Schema.Type.Float: + return typeof(float); + case Schema.Type.Double: + return typeof(double); + case Schema.Type.Bytes: + return typeof(byte[]); + case Schema.Type.String: + return typeof(string); + case Schema.Type.Union: + { + if (schema is UnionSchema unSchema && unSchema.Count == 2) { - if (schema is UnionSchema unSchema && unSchema.Count == 2) - { - Schema s1 = unSchema.Schemas[0]; - Schema s2 = unSchema.Schemas[1]; + Schema s1 = unSchema.Schemas[0]; + Schema s2 = unSchema.Schemas[1]; - // Nullable ? - Type itemType = null; - if (s1.Tag == Schema.Type.Null) - { - itemType = GetType(s2); - } - else if (s2.Tag == Schema.Type.Null) - { - itemType = GetType(s1); - } + // Nullable ? + Type itemType = null; + if (s1.Tag == Schema.Type.Null) + { + itemType = GetType(s2); + } + else if (s2.Tag == Schema.Type.Null) + { + itemType = GetType(s1); + } - if (itemType != null) + if (itemType != null) { if (itemType.IsValueType && !itemType.IsEnum) { From 88086026508b407dd3206481e08971372da1afa6 Mon Sep 17 00:00:00 2001 From: "karyna.bilotska" Date: Thu, 15 Aug 2024 18:41:19 +0200 Subject: [PATCH 3/3] AVRO-4028: [c#] remove formatting changes --- .../src/apache/main/Specific/ObjectCreator.cs | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/lang/csharp/src/apache/main/Specific/ObjectCreator.cs b/lang/csharp/src/apache/main/Specific/ObjectCreator.cs index 5312c01df14..d0c794bb41f 100644 --- a/lang/csharp/src/apache/main/Specific/ObjectCreator.cs +++ b/lang/csharp/src/apache/main/Specific/ObjectCreator.cs @@ -248,7 +248,7 @@ private bool TryGetNullableItemTypeName(string name, out string itemTypeName) /// public Type GetType(Schema schema) { - switch (schema.Tag) { + switch(schema.Tag) { case Schema.Type.Null: break; case Schema.Type.Boolean: @@ -284,51 +284,51 @@ public Type GetType(Schema schema) } if (itemType != null) + { + if (itemType.IsValueType && !itemType.IsEnum) { - if (itemType.IsValueType && !itemType.IsEnum) + try + { + return GenericNullableType.MakeGenericType(itemType); + } + catch { - try - { - return GenericNullableType.MakeGenericType(itemType); - } - catch - { - } } - - return itemType; } - } - return typeof(object); + return itemType; + } } - case Schema.Type.Array: - { - ArraySchema arrSchema = schema as ArraySchema; - Type itemSchema = GetType(arrSchema.ItemSchema); - return GenericListType.MakeGenericType(itemSchema); - } - case Schema.Type.Map: - { - MapSchema mapSchema = schema as MapSchema; - Type itemSchema = GetType(mapSchema.ValueSchema); + return typeof(object); + } + case Schema.Type.Array: + { + ArraySchema arrSchema = schema as ArraySchema; + Type itemSchema = GetType(arrSchema.ItemSchema); - return GenericMapType.MakeGenericType(typeof(string), itemSchema); - } - case Schema.Type.Enumeration: - case Schema.Type.Record: - case Schema.Type.Fixed: - case Schema.Type.Error: - { - // Should all be named types - if (schema is NamedSchema named) - { - return FindType(named.Fullname); - } + return GenericListType.MakeGenericType(itemSchema); + } + case Schema.Type.Map: + { + MapSchema mapSchema = schema as MapSchema; + Type itemSchema = GetType(mapSchema.ValueSchema); - break; + return GenericMapType.MakeGenericType(typeof(string), itemSchema ); + } + case Schema.Type.Enumeration: + case Schema.Type.Record: + case Schema.Type.Fixed: + case Schema.Type.Error: + { + // Should all be named types + if (schema is NamedSchema named) + { + return FindType(named.Fullname); } + + break; + } } // Fallback