diff --git a/ReflectorNet.Tests.OuterAssembly/src/Model/TypeIdTestModels.cs b/ReflectorNet.Tests.OuterAssembly/src/Model/TypeIdTestModels.cs new file mode 100644 index 00000000..546bf21b --- /dev/null +++ b/ReflectorNet.Tests.OuterAssembly/src/Model/TypeIdTestModels.cs @@ -0,0 +1,195 @@ +/* + * ReflectorNet + * Author: Ivan Murzak (https://github.com/IvanMurzak) + * Copyright (c) 2025 Ivan Murzak + * Licensed under the Apache License, Version 2.0. See LICENSE file in the project root for full license information. + */ + +namespace com.IvanMurzak.ReflectorNet.OuterAssembly.Model +{ + // Simple class + public class OuterSimpleClass + { + public int Value { get; set; } + } + + // Simple struct + public struct OuterSimpleStruct + { + public int Value { get; set; } + } + + // Abstract class + public abstract class OuterAbstractClass + { + public abstract int Value { get; set; } + } + + // Sealed class + public sealed class OuterSealedClass + { + public int Value { get; set; } + } + + // Static class (cannot be used as type argument, but can be referenced) + public static class OuterStaticClass + { + public static int Value { get; set; } + } + + // Generic class with single type parameter + public class OuterGenericClass + { + public T? Value { get; set; } + } + + // Generic class with two type parameters + public class OuterGenericClass2 + { + public T1? Value1 { get; set; } + public T2? Value2 { get; set; } + } + + // Generic class with three type parameters + public class OuterGenericClass3 + { + public T1? Value1 { get; set; } + public T2? Value2 { get; set; } + public T3? Value3 { get; set; } + } + + // Generic struct + public struct OuterGenericStruct + { + public T? Value { get; set; } + } + + // Generic struct with two type parameters + public struct OuterGenericStruct2 + { + public T1? Value1 { get; set; } + public T2? Value2 { get; set; } + } + + // Container class with nested types + public class OuterContainer + { + // Nested class + public class NestedClass + { + public int Value { get; set; } + } + + // Nested struct + public struct NestedStruct + { + public int Value { get; set; } + } + + // Nested abstract class + public abstract class NestedAbstractClass + { + public abstract int Value { get; set; } + } + + // Nested sealed class + public sealed class NestedSealedClass + { + public int Value { get; set; } + } + + // Nested generic class + public class NestedGenericClass + { + public T? Value { get; set; } + } + + // Nested generic struct + public struct NestedGenericStruct + { + public T? Value { get; set; } + } + + // Double nested container + public class NestedContainer + { + // Double nested class + public class DoubleNestedClass + { + public int Value { get; set; } + } + + // Double nested struct + public struct DoubleNestedStruct + { + public int Value { get; set; } + } + + // Double nested generic + public class DoubleNestedGenericClass + { + public T? Value { get; set; } + } + } + } + + // Generic container with nested types + public class OuterGenericContainer + { + public class NestedInGeneric + { + public T? Value { get; set; } + } + + public struct NestedStructInGeneric + { + public T? Value { get; set; } + } + + public class NestedGenericInGeneric + { + public T? Value1 { get; set; } + public U? Value2 { get; set; } + } + } + + // Interface + public interface IOuterInterface + { + int Value { get; set; } + } + + // Generic interface + public interface IOuterGenericInterface + { + T? Value { get; set; } + } + + // Enum + public enum OuterEnum + { + None = 0, + First = 1, + Second = 2 + } + + // Flags enum + [System.Flags] + public enum OuterFlagsEnum + { + None = 0, + Flag1 = 1, + Flag2 = 2, + Flag3 = 4 + } + + // Nested enum container + public class OuterEnumContainer + { + public enum NestedEnum + { + None = 0, + Value = 1 + } + } +} diff --git a/ReflectorNet.Tests/src/ReflectorTests/SerializationTests.cs b/ReflectorNet.Tests/src/ReflectorTests/SerializationTests.cs index e2fc25b1..842f08b3 100644 --- a/ReflectorNet.Tests/src/ReflectorTests/SerializationTests.cs +++ b/ReflectorNet.Tests/src/ReflectorTests/SerializationTests.cs @@ -188,7 +188,7 @@ public void Serialize_ParentClass_NestedClass_Instance() // Assert Assert.NotNull(serialized); - Assert.Equal(typeof(ParentClass.NestedClass).GetTypeName(pretty: false), serialized.typeName); + Assert.Equal(typeof(ParentClass.NestedClass).GetTypeId(), serialized.typeName); Assert.NotNull(serialized.valueJsonElement); _output.WriteLine($"Serialized ParentClass.NestedClass: {serialized.ToJson(reflector)}"); } @@ -232,7 +232,7 @@ public void Serialize_StaticParentClass_NestedClass_Instance() // Assert Assert.NotNull(serialized); - Assert.Equal(typeof(StaticParentClass.NestedClass).GetTypeName(pretty: false), serialized.typeName); + Assert.Equal(typeof(StaticParentClass.NestedClass).GetTypeId(), serialized.typeName); Assert.NotNull(serialized.valueJsonElement); _output.WriteLine($"Serialized StaticParentClass.NestedClass: {serialized.ToJson(reflector)}"); } @@ -332,7 +332,7 @@ public void Serialize_NestedClass_WithDefaultValues() // Assert Assert.NotNull(serialized); - Assert.Equal(typeof(ParentClass.NestedClass).GetTypeName(pretty: false), serialized.typeName); + Assert.Equal(typeof(ParentClass.NestedClass).GetTypeId(), serialized.typeName); _output.WriteLine($"Serialized nested class with defaults: {serialized.ToJson(reflector)}"); } @@ -370,7 +370,7 @@ public void Serialize_NestedClass_WithNullValues() // Assert Assert.NotNull(serialized); - Assert.Equal(typeof(ParentClass.NestedClass).GetTypeName(pretty: false), serialized.typeName); + Assert.Equal(typeof(ParentClass.NestedClass).GetTypeId(), serialized.typeName); _output.WriteLine($"Serialized nested class with empty strings: {serialized.ToJson(reflector)}"); } @@ -415,8 +415,8 @@ public void Serialize_Static_Members_From_ParentClass_NestedClass() Assert.NotNull(serializedProperty); Assert.Equal("NestedStaticField", serializedField.name); Assert.Equal("NestedStaticProperty", serializedProperty.name); - Assert.Equal(typeof(string).GetTypeName(pretty: false), serializedField.typeName); - Assert.Equal(typeof(string).GetTypeName(pretty: false), serializedProperty.typeName); + Assert.Equal(typeof(string).GetTypeId(), serializedField.typeName); + Assert.Equal(typeof(string).GetTypeId(), serializedProperty.typeName); _output.WriteLine($"Serialized static field: {serializedField.ToJson(reflector)}"); _output.WriteLine($"Serialized static property: {serializedProperty.ToJson(reflector)}"); @@ -441,8 +441,8 @@ public void Serialize_Static_Members_From_ParentClass_NestedStaticClass() Assert.NotNull(serializedProperty); Assert.Equal("NestedStaticField", serializedField.name); Assert.Equal("NestedStaticProperty", serializedProperty.name); - Assert.Equal(typeof(string).GetTypeName(pretty: false), serializedField.typeName); - Assert.Equal(typeof(string).GetTypeName(pretty: false), serializedProperty.typeName); + Assert.Equal(typeof(string).GetTypeId(), serializedField.typeName); + Assert.Equal(typeof(string).GetTypeId(), serializedProperty.typeName); _output.WriteLine($"Serialized ParentClass.NestedStaticClass static field: {serializedField.ToJson(reflector)}"); _output.WriteLine($"Serialized ParentClass.NestedStaticClass static property: {serializedProperty.ToJson(reflector)}"); @@ -467,8 +467,8 @@ public void Serialize_Static_Members_From_StaticParentClass_NestedClass() Assert.NotNull(serializedProperty); Assert.Equal("NestedStaticField", serializedField.name); Assert.Equal("NestedStaticProperty", serializedProperty.name); - Assert.Equal(typeof(string).GetTypeName(pretty: false), serializedField.typeName); - Assert.Equal(typeof(string).GetTypeName(pretty: false), serializedProperty.typeName); + Assert.Equal(typeof(string).GetTypeId(), serializedField.typeName); + Assert.Equal(typeof(string).GetTypeId(), serializedProperty.typeName); _output.WriteLine($"Serialized StaticParentClass.NestedClass static field: {serializedField.ToJson(reflector)}"); _output.WriteLine($"Serialized StaticParentClass.NestedClass static property: {serializedProperty.ToJson(reflector)}"); @@ -493,8 +493,8 @@ public void Serialize_Static_Members_From_StaticParentClass_NestedStaticClass() Assert.NotNull(serializedProperty); Assert.Equal("NestedStaticField", serializedField.name); Assert.Equal("NestedStaticProperty", serializedProperty.name); - Assert.Equal(typeof(string).GetTypeName(pretty: false), serializedField.typeName); - Assert.Equal(typeof(string).GetTypeName(pretty: false), serializedProperty.typeName); + Assert.Equal(typeof(string).GetTypeId(), serializedField.typeName); + Assert.Equal(typeof(string).GetTypeId(), serializedProperty.typeName); _output.WriteLine($"Serialized StaticParentClass.NestedStaticClass static field: {serializedField.ToJson(reflector)}"); _output.WriteLine($"Serialized StaticParentClass.NestedStaticClass static property: {serializedProperty.ToJson(reflector)}"); diff --git a/ReflectorNet.Tests/src/ReflectorTests/SerializeDeserializationTests.cs b/ReflectorNet.Tests/src/ReflectorTests/SerializeDeserializationTests.cs index 7bdfc0b8..de9ca113 100644 --- a/ReflectorNet.Tests/src/ReflectorTests/SerializeDeserializationTests.cs +++ b/ReflectorNet.Tests/src/ReflectorTests/SerializeDeserializationTests.cs @@ -25,7 +25,7 @@ void ActAssert(object? original, Type? fallbackType = null) var type = original?.GetType() ?? fallbackType; - _output.WriteLine($"### Test for type: {type?.GetTypeName(pretty: true) ?? "null"}\n"); + _output.WriteLine($"### Test for type: {type?.GetTypeId() ?? "null"}\n"); _output.WriteLine($"Serialization:\n{serializeLogger}"); var deserializeLogger = new StringBuilderLogger(); diff --git a/ReflectorNet.Tests/src/ReflectorTests/TypeAndAssemblySerializationTests.cs b/ReflectorNet.Tests/src/ReflectorTests/TypeAndAssemblySerializationTests.cs index 36bcfe54..d849a781 100644 --- a/ReflectorNet.Tests/src/ReflectorTests/TypeAndAssemblySerializationTests.cs +++ b/ReflectorNet.Tests/src/ReflectorTests/TypeAndAssemblySerializationTests.cs @@ -31,7 +31,7 @@ void ActAssert(object? original, Type? fallbackType = null) var type = original?.GetType() ?? fallbackType; - _output.WriteLine($"### Test for type: {type?.GetTypeName(pretty: true) ?? "null"}\n"); + _output.WriteLine($"### Test for type: {type?.GetTypeId() ?? "null"}\n"); _output.WriteLine($"Serialization:\n{serializeLogger}"); var deserializeLogger = new StringBuilderLogger(); @@ -49,12 +49,12 @@ void ActAssert(object? original, Type? fallbackType = null) // For System.Type and System.Reflection.Assembly, we verify the essential identity information if (original is Type originalType && deserialized is Type deserializedType) { - _output.WriteLine($"Original Type: {originalType.FullName}"); - _output.WriteLine($"Deserialized Type: {deserializedType.FullName}"); + _output.WriteLine($"Original Type: {originalType.GetTypeId()}"); + _output.WriteLine($"Deserialized Type: {deserializedType.GetTypeId()}"); _output.WriteLine($"Original Assembly: {originalType.Assembly.FullName}"); _output.WriteLine($"Deserialized Assembly: {deserializedType.Assembly.FullName}"); - Assert.Equal(originalType.FullName, deserializedType.FullName); + Assert.Equal(originalType.GetTypeId(), deserializedType.GetTypeId()); Assert.Equal(originalType.Assembly.FullName, deserializedType.Assembly.FullName); Assert.Equal(originalType, deserializedType); } diff --git a/ReflectorNet.Tests/src/ReflectorTests/TypedListDeserializationTests.cs b/ReflectorNet.Tests/src/ReflectorTests/TypedListDeserializationTests.cs index 91ff352a..593a3904 100644 --- a/ReflectorNet.Tests/src/ReflectorTests/TypedListDeserializationTests.cs +++ b/ReflectorNet.Tests/src/ReflectorTests/TypedListDeserializationTests.cs @@ -227,7 +227,7 @@ public void DirectListDeserializationViaSerializedMember_ShouldBeTyped() // Assert Assert.NotNull(deserialized); - _output.WriteLine($"Deserialized type: {deserialized.GetType().FullName}"); + _output.WriteLine($"Deserialized type: {deserialized.GetType().GetTypeId()}"); // Critical: Should be List, not List Assert.IsType>(deserialized); diff --git a/ReflectorNet.Tests/src/SchemaTests/AdvancedFeatureTests.cs b/ReflectorNet.Tests/src/SchemaTests/AdvancedFeatureTests.cs index 70f54aba..fdee277a 100644 --- a/ReflectorNet.Tests/src/SchemaTests/AdvancedFeatureTests.cs +++ b/ReflectorNet.Tests/src/SchemaTests/AdvancedFeatureTests.cs @@ -31,7 +31,7 @@ public void Property_vs_Field_Serialization() Assert.NotNull(propertiesOnly); Assert.NotNull(fieldsOnly); Assert.NotNull(allMembers); - Assert.Equal(typeof(GameObjectRef).GetTypeName(pretty: false), propertiesOnly.typeName); + Assert.Equal(typeof(GameObjectRef).GetTypeId(), propertiesOnly.typeName); _output.WriteLine($"Properties serialization: {propertiesOnly.typeName}"); _output.WriteLine($"Fields serialization: {fieldsOnly.typeName}"); diff --git a/ReflectorNet.Tests/src/SchemaTests/MethodFindingTests.cs b/ReflectorNet.Tests/src/SchemaTests/MethodFindingTests.cs index bcf7f0ab..96b16364 100644 --- a/ReflectorNet.Tests/src/SchemaTests/MethodFindingTests.cs +++ b/ReflectorNet.Tests/src/SchemaTests/MethodFindingTests.cs @@ -79,7 +79,7 @@ public void FindMethod_WithParameterMatching() MethodName = nameof(TestClass.SerializedMemberList_ReturnString), InputParameters = new List { - new() { TypeName = typeof(SerializedMemberList).GetTypeName(pretty: false), Name = "gameObjectDiffs" } + new() { TypeName = typeof(SerializedMemberList).GetTypeId(), Name = "gameObjectDiffs" } } }; diff --git a/ReflectorNet.Tests/src/SchemaTests/PerformanceTests.cs b/ReflectorNet.Tests/src/SchemaTests/PerformanceTests.cs index 44a146ca..2babfb42 100644 --- a/ReflectorNet.Tests/src/SchemaTests/PerformanceTests.cs +++ b/ReflectorNet.Tests/src/SchemaTests/PerformanceTests.cs @@ -90,7 +90,7 @@ public void Reflector_Introspection_Tests() Assert.NotNull(typeId); Assert.Equal("com.IvanMurzak.ReflectorNet.Tests.Model.GameObjectRef", typeId); - _output.WriteLine($"Type: {testType.GetTypeName(pretty: false)}"); + _output.WriteLine($"Type: {testType.GetTypeId()}"); _output.WriteLine($"Schema: {schema}"); _output.WriteLine($"TypeId: {typeId}"); } @@ -104,7 +104,7 @@ public void TypeUtils_Integration_Tests() var stringType = TypeUtils.GetType("System.String"); Assert.Equal(typeof(string), stringType); - var gameObjectRefType = TypeUtils.GetType(typeof(GameObjectRef).GetTypeName(pretty: false)!); + var gameObjectRefType = TypeUtils.GetType(typeof(GameObjectRef).GetTypeId()!); Assert.Equal(typeof(GameObjectRef), gameObjectRefType); // Test default value generation @@ -166,7 +166,7 @@ public void MethodDataRef_Construction_From_MethodInfo() Assert.Equal(nameof(TestClass.SerializedMemberList_ReturnString), methodDataRef.MethodName); Assert.Equal(methodInfo.IsPublic, methodDataRef.IsPublic); Assert.Equal(methodInfo.IsStatic, methodDataRef.IsStatic); - Assert.Equal(methodInfo.ReturnType.GetTypeName(pretty: false), methodDataRef.ReturnType); + Assert.Equal(methodInfo.ReturnType.GetTypeId(), methodDataRef.ReturnType); Assert.NotNull(methodDataRef.ReturnSchema); Assert.NotNull(methodDataRef.InputParametersSchema); Assert.Single(methodDataRef.InputParametersSchema); // SerializedMemberList parameter diff --git a/ReflectorNet.Tests/src/SchemaTests/SchemaSerializationValidationTests.cs b/ReflectorNet.Tests/src/SchemaTests/SchemaSerializationValidationTests.cs index 0ed13eec..8859f3d2 100644 --- a/ReflectorNet.Tests/src/SchemaTests/SchemaSerializationValidationTests.cs +++ b/ReflectorNet.Tests/src/SchemaTests/SchemaSerializationValidationTests.cs @@ -24,7 +24,7 @@ public SchemaSerializationValidationTests(ITestOutputHelper output) : base(outpu /// private void ValidateTypeSchemaAndRoundTrip(Type type, object? instance, Reflector reflector) { - var typeName = type.GetTypeName(pretty: true); + var typeName = type.GetTypeId(); _output.WriteLine($"=== Testing type: {typeName} ==="); // Step 1: Generate schema and validate it has no errors diff --git a/ReflectorNet.Tests/src/SchemaTests/SerializationTests.cs b/ReflectorNet.Tests/src/SchemaTests/SerializationTests.cs index ea4aaeb8..682f7533 100644 --- a/ReflectorNet.Tests/src/SchemaTests/SerializationTests.cs +++ b/ReflectorNet.Tests/src/SchemaTests/SerializationTests.cs @@ -27,7 +27,7 @@ public void Serialize_GameObjectRef() // Assert Assert.NotNull(serialized); - Assert.Equal(typeof(GameObjectRef).GetTypeName(pretty: false), serialized.typeName); + Assert.Equal(typeof(GameObjectRef).GetTypeId(), serialized.typeName); Assert.NotNull(serialized.valueJsonElement); _output.WriteLine($"Serialized GameObjectRef: {serialized.ToJson(reflector)}"); } @@ -75,7 +75,7 @@ public void Serialize_StringArray() // Assert Assert.NotNull(serialized); - Assert.Equal(typeof(string[]).GetTypeName(pretty: false), serialized.typeName); + Assert.Equal(typeof(string[]).GetTypeId(), serialized.typeName); _output.WriteLine($"Serialized string array: {serialized.ToJson(reflector)}"); } @@ -111,7 +111,7 @@ public void Serialize_Null_Value() // Assert Assert.NotNull(serialized); - Assert.Equal(typeof(GameObjectRef).GetTypeName(pretty: false), serialized.typeName); + Assert.Equal(typeof(GameObjectRef).GetTypeId(), serialized.typeName); Assert.Null(serialized.valueJsonElement); _output.WriteLine($"Serialized null value: {serialized.ToJson(reflector)}"); } @@ -125,7 +125,7 @@ public void Deserialize_Null_Value() // Create a SerializedMember with null value var serialized = new SerializedMember { - typeName = typeof(GameObjectRef).GetTypeName(pretty: false)!, + typeName = typeof(GameObjectRef).GetTypeId()!, valueJsonElement = null }; @@ -154,7 +154,7 @@ public void Serialize_GameObjectRefList() // Assert Assert.NotNull(serialized); - Assert.Equal(typeof(GameObjectRefList).GetTypeName(pretty: false), serialized.typeName); + Assert.Equal(typeof(GameObjectRefList).GetTypeId(), serialized.typeName); _output.WriteLine($"Serialized GameObjectRefList: {serialized.ToJson(reflector)}"); } @@ -200,7 +200,7 @@ public void Serialize_EmptyArray() // Assert Assert.NotNull(serialized); - Assert.Equal(typeof(string[]).GetTypeName(pretty: false), serialized.typeName); + Assert.Equal(typeof(string[]).GetTypeId(), serialized.typeName); _output.WriteLine($"Serialized empty array: {serialized.ToJson(reflector)}"); } @@ -237,8 +237,8 @@ public void Serialization_BindingFlags_Control() // Assert Assert.NotNull(publicOnlySerialized); Assert.NotNull(allMembersSerialized); - Assert.Equal(typeof(TestClass).GetTypeName(pretty: false), publicOnlySerialized.typeName); - Assert.Equal(typeof(TestClass).GetTypeName(pretty: false), allMembersSerialized.typeName); + Assert.Equal(typeof(TestClass).GetTypeId(), publicOnlySerialized.typeName); + Assert.Equal(typeof(TestClass).GetTypeId(), allMembersSerialized.typeName); _output.WriteLine("BindingFlags serialization control test passed"); } diff --git a/ReflectorNet.Tests/src/SchemaTests/TestSchemaTypeId.cs b/ReflectorNet.Tests/src/SchemaTests/TestSchemaTypeId.cs index a718637a..06372e53 100644 --- a/ReflectorNet.Tests/src/SchemaTests/TestSchemaTypeId.cs +++ b/ReflectorNet.Tests/src/SchemaTests/TestSchemaTypeId.cs @@ -64,131 +64,6 @@ public void GetSchemaTypeId_StringArray_ShouldWorkForAnyType() _output.WriteLine($"string[] -> {result}"); } - [Fact] - public void GetSchemaTypeId_ListOfInt_ShouldNormalizeToArray() - { - // Arrange - var listType = typeof(List); - var arrayType = typeof(int[]); - - // Act - var listResult = listType.GetSchemaTypeId(); - var arrayResult = arrayType.GetSchemaTypeId(); - - // Assert - Assert.Equal(arrayResult, listResult); - Assert.Equal($"System.Int32{TypeUtils.ArraySuffix}", listResult); - _output.WriteLine($"List -> {listResult}"); - _output.WriteLine($"int[] -> {arrayResult}"); - _output.WriteLine($"Both should be equal: {listResult == arrayResult}"); - } - - [Fact] - public void GetSchemaTypeId_ListOfString_ShouldMatchStringArray() - { - // Arrange - var listType = typeof(List); - var arrayType = typeof(string[]); - - // Act - var listResult = listType.GetSchemaTypeId(); - var arrayResult = arrayType.GetSchemaTypeId(); - - // Assert - Assert.Equal(arrayResult, listResult); - Assert.Equal($"System.String{TypeUtils.ArraySuffix}", listResult); - _output.WriteLine($"List -> {listResult}"); - _output.WriteLine($"string[] -> {arrayResult}"); - } - - [Fact] - public void GetSchemaTypeId_ListOfIntArray_ShouldNormalizeToDoubleArray() - { - // Arrange - var type = typeof(List); - - // Act - var result = type.GetSchemaTypeId(); - - // Assert - Assert.Equal($"System.Int32{TypeUtils.ArraySuffix}{TypeUtils.ArraySuffix}", result); - _output.WriteLine($"List -> {result}"); - } - - [Fact] - public void GetSchemaTypeId_ListOfListOfInt_ShouldNormalizeToDoubleArray() - { - // Arrange - var type = typeof(List>); - - // Act - var result = type.GetSchemaTypeId(); - - // Assert - Assert.Equal($"System.Int32{TypeUtils.ArraySuffix}{TypeUtils.ArraySuffix}", result); - _output.WriteLine($"List> -> {result}"); - } - - [Fact] - public void GetSchemaTypeId_ListOfListOfInt_ShouldMatchIntDoubleArray() - { - // Arrange - var listType = typeof(List>); - var arrayType = typeof(int[][]); - - // Act - var listResult = listType.GetSchemaTypeId(); - var arrayResult = arrayType.GetSchemaTypeId(); - - // Assert - Assert.Equal(arrayResult, listResult); - Assert.Equal($"System.Int32{TypeUtils.ArraySuffix}{TypeUtils.ArraySuffix}", listResult); - _output.WriteLine($"List> -> {listResult}"); - _output.WriteLine($"int[][] -> {arrayResult}"); - } - - [Fact] - public void GetSchemaTypeId_ListOfDoubleNestedArray_ShouldAppendThreeArrays() - { - // Arrange - var type = typeof(List); - - // Act - var result = type.GetSchemaTypeId(); - - // Assert - Assert.Equal($"System.Int32{TypeUtils.ArraySuffix}{TypeUtils.ArraySuffix}{TypeUtils.ArraySuffix}", result); - _output.WriteLine($"List -> {result}"); - } - - [Fact] - public void GetSchemaTypeId_ListOfStringArray_ShouldWorkForAnyType() - { - // Arrange - var type = typeof(List); - - // Act - var result = type.GetSchemaTypeId(); - - // Assert - Assert.Equal($"System.String{TypeUtils.ArraySuffix}{TypeUtils.ArraySuffix}", result); - _output.WriteLine($"List -> {result}"); - } - - [Fact] - public void GetSchemaTypeId_ComplexNestedCollections_ShouldHandleDeepNesting() - { - // Arrange - var type = typeof(List[]>); - - // Act - var result = type.GetSchemaTypeId(); - - // Assert - Assert.Equal($"System.String{TypeUtils.ArraySuffix}{TypeUtils.ArraySuffix}{TypeUtils.ArraySuffix}{TypeUtils.ArraySuffix}", result); - _output.WriteLine($"List[]> -> {result}"); - } - [Fact] public void GetSchemaTypeId_NonCollectionType_ShouldReturnFullName() { @@ -273,98 +148,6 @@ public void GetSchemaTypeId_IListOfInt_ShouldReturnGenericFormat() _output.WriteLine($"IList -> {result}"); } - [Fact] - public void GetSchemaTypeId_HashSetOfInt_ShouldNormalizeToArray() - { - // Arrange - var type = typeof(HashSet); - - // Act - var result = type.GetSchemaTypeId(); - - // Assert - Assert.Equal($"System.Int32{TypeUtils.ArraySuffix}", result); - _output.WriteLine($"HashSet -> {result}"); - } - - [Fact] - public void GetSchemaTypeId_SortedSetOfString_ShouldNormalizeToArray() - { - // Arrange - var type = typeof(SortedSet); - - // Act - var result = type.GetSchemaTypeId(); - - // Assert - Assert.Equal($"System.String{TypeUtils.ArraySuffix}", result); - _output.WriteLine($"SortedSet -> {result}"); - } - - [Fact] - public void GetSchemaTypeId_LinkedListOfInt_ShouldNormalizeToArray() - { - // Arrange - var type = typeof(LinkedList); - - // Act - var result = type.GetSchemaTypeId(); - - // Assert - Assert.Equal($"System.Int32{TypeUtils.ArraySuffix}", result); - _output.WriteLine($"LinkedList -> {result}"); - } - - [Fact] - public void GetSchemaTypeId_QueueOfString_ShouldNormalizeToArray() - { - // Arrange - var type = typeof(Queue); - - // Act - var result = type.GetSchemaTypeId(); - - // Assert - Assert.Equal($"System.String{TypeUtils.ArraySuffix}", result); - _output.WriteLine($"Queue -> {result}"); - } - - [Fact] - public void GetSchemaTypeId_StackOfInt_ShouldNormalizeToArray() - { - // Arrange - var type = typeof(Stack); - - // Act - var result = type.GetSchemaTypeId(); - - // Assert - Assert.Equal($"System.Int32{TypeUtils.ArraySuffix}", result); - _output.WriteLine($"Stack -> {result}"); - } - - [Fact] - public void GetSchemaTypeId_NestedGenericCollections_AllShouldNormalize() - { - // Arrange - var listOfHashSet = typeof(List>); - var queueOfStack = typeof(Queue>); - var arrayOfLinkedList = typeof(LinkedList[]); - - // Act - var result1 = listOfHashSet.GetSchemaTypeId(); - var result2 = queueOfStack.GetSchemaTypeId(); - var result3 = arrayOfLinkedList.GetSchemaTypeId(); - - // Assert - Assert.Equal($"System.Int32{TypeUtils.ArraySuffix}{TypeUtils.ArraySuffix}", result1); - Assert.Equal($"System.String{TypeUtils.ArraySuffix}{TypeUtils.ArraySuffix}", result2); - Assert.Equal($"System.Double{TypeUtils.ArraySuffix}{TypeUtils.ArraySuffix}", result3); - _output.WriteLine($"List> -> {result1}"); - _output.WriteLine($"Queue> -> {result2}"); - _output.WriteLine($"LinkedList[] -> {result3}"); - } - [Fact] public void GetSchemaTypeId_CustomClass_ShouldReturnFullName() { @@ -379,20 +162,6 @@ public void GetSchemaTypeId_CustomClass_ShouldReturnFullName() _output.WriteLine($"TestType -> {result}"); } - [Fact] - public void GetSchemaTypeId_ListOfCustomClass_ShouldNormalizeToArray() - { - // Arrange - var type = typeof(List); - - // Act - var result = type.GetSchemaTypeId(); - - // Assert - Assert.Equal($"com.IvanMurzak.ReflectorNet.Tests.SchemaTests.TestType{TypeUtils.ArraySuffix}", result); - _output.WriteLine($"List -> {result}"); - } - [Fact] public void GetSchemaTypeId_ArrayOfCustomClass_ShouldAppendArray() { @@ -406,23 +175,5 @@ public void GetSchemaTypeId_ArrayOfCustomClass_ShouldAppendArray() Assert.Equal($"com.IvanMurzak.ReflectorNet.Tests.SchemaTests.TestType{TypeUtils.ArraySuffix}", result); _output.WriteLine($"TestType[] -> {result}"); } - - [Fact] - public void GetSchemaTypeId_ListAndArrayOfCustomClass_ShouldMatch() - { - // Arrange - var listType = typeof(List); - var arrayType = typeof(TestType[]); - - // Act - var listResult = listType.GetSchemaTypeId(); - var arrayResult = arrayType.GetSchemaTypeId(); - - // Assert - Assert.Equal(arrayResult, listResult); - Assert.Equal($"com.IvanMurzak.ReflectorNet.Tests.SchemaTests.TestType{TypeUtils.ArraySuffix}", listResult); - _output.WriteLine($"List -> {listResult}"); - _output.WriteLine($"TestType[] -> {arrayResult}"); - } } } diff --git a/ReflectorNet.Tests/src/SchemaTests/TestType.cs b/ReflectorNet.Tests/src/SchemaTests/TestType.cs index c5cb9ff5..13caa5f6 100644 --- a/ReflectorNet.Tests/src/SchemaTests/TestType.cs +++ b/ReflectorNet.Tests/src/SchemaTests/TestType.cs @@ -17,7 +17,7 @@ public void Generic_SerializedMemberList() var type = typeof(SerializedMemberList); var genericTypes = TypeUtils.GetGenericTypes(type).ToList(); - _output.WriteLine($"Generic types for {type.GetTypeName(pretty: true)}: {string.Join(", ", genericTypes.Select(t => t.GetTypeName(pretty: true)))}"); + _output.WriteLine($"Generic types for {type.GetTypeId()}: {string.Join(", ", genericTypes.Select(t => t.GetTypeId()))}"); Assert.NotEmpty(genericTypes); @@ -31,7 +31,7 @@ public void Generic_List_SerializedMemberList() var type = typeof(List); var genericTypes = TypeUtils.GetGenericTypes(type).ToList(); - _output.WriteLine($"Generic types for {type.GetTypeName(pretty: true)}: {string.Join(", ", genericTypes.Select(t => t.GetTypeName(pretty: true)))}"); + _output.WriteLine($"Generic types for {type.GetTypeId()}: {string.Join(", ", genericTypes.Select(t => t.GetTypeId()))}"); Assert.NotEmpty(genericTypes); @@ -48,7 +48,7 @@ public void Generic_List_SerializedMember() var type = typeof(List); var genericTypes = TypeUtils.GetGenericTypes(type).ToList(); - _output.WriteLine($"Generic types for {type.GetTypeName(pretty: true)}: {string.Join(", ", genericTypes.Select(t => t.GetTypeName(pretty: true)))}"); + _output.WriteLine($"Generic types for {type.GetTypeId()}: {string.Join(", ", genericTypes.Select(t => t.GetTypeId()))}"); Assert.NotEmpty(genericTypes); @@ -57,22 +57,17 @@ public void Generic_List_SerializedMember() Assert.Equal(1, genericTypes.Count(x => x == typeof(SerializedMember))); } - void TestTypeName(Type type) + void TestTypeSanitize(Type type) { - var typeName = TypeUtils.GetTypeName(type, pretty: false); - Assert.Equal(type, TypeUtils.GetType(typeName)); - - typeName = TypeUtils.GetTypeName(type, pretty: true); + var typeName = TypeUtils.Sanitize(type); Assert.Equal(type, TypeUtils.GetType(typeName)); } - - [Fact] public void GetTypeName_OuterAssembly() { - TestTypeName(typeof(OuterAssembly.Model.ParentClass)); - TestTypeName(typeof(OuterAssembly.Model.ParentClass.NestedClass)); + TestTypeSanitize(typeof(OuterAssembly.Model.ParentClass)); + TestTypeSanitize(typeof(OuterAssembly.Model.ParentClass.NestedClass)); } } } diff --git a/ReflectorNet.Tests/src/TypeUtilsTests/GetTypeIdTests.cs b/ReflectorNet.Tests/src/TypeUtilsTests/GetTypeIdTests.cs new file mode 100644 index 00000000..607be57f --- /dev/null +++ b/ReflectorNet.Tests/src/TypeUtilsTests/GetTypeIdTests.cs @@ -0,0 +1,512 @@ +/* + * ReflectorNet + * Author: Ivan Murzak (https://github.com/IvanMurzak) + * Copyright (c) 2025 Ivan Murzak + * Licensed under the Apache License, Version 2.0. See LICENSE file in the project root for full license information. + */ + +using System; +using System.Collections.Generic; +using com.IvanMurzak.ReflectorNet.Model; +using com.IvanMurzak.ReflectorNet.OuterAssembly.Model; +using com.IvanMurzak.ReflectorNet.Tests.Model; +using com.IvanMurzak.ReflectorNet.Utils; +using Xunit; +using Xunit.Abstractions; + +namespace com.IvanMurzak.ReflectorNet.Tests.TypeUtilsTests +{ + /// + /// Tests for TypeUtils.GetTypeId() method. + /// Verifies that types are correctly converted to their string representation. + /// + public class GetTypeIdTests : BaseTest + { + public GetTypeIdTests(ITestOutputHelper output) : base(output) { } + + #region Test Data - Built-in .NET Types + + /// + /// Built-in .NET primitive and common types. + /// + public static readonly Dictionary BuiltInTypes = new Dictionary + { + // Primitive types + ["System.Boolean"] = typeof(bool), + ["System.Byte"] = typeof(byte), + ["System.SByte"] = typeof(sbyte), + ["System.Int16"] = typeof(short), + ["System.UInt16"] = typeof(ushort), + ["System.Int32"] = typeof(int), + ["System.UInt32"] = typeof(uint), + ["System.Int64"] = typeof(long), + ["System.UInt64"] = typeof(ulong), + ["System.Single"] = typeof(float), + ["System.Double"] = typeof(double), + ["System.Decimal"] = typeof(decimal), + ["System.Char"] = typeof(char), + ["System.String"] = typeof(string), + ["System.Object"] = typeof(object), + + // Common value types + ["System.DateTime"] = typeof(DateTime), + ["System.DateTimeOffset"] = typeof(DateTimeOffset), + ["System.TimeSpan"] = typeof(TimeSpan), + ["System.Guid"] = typeof(Guid), + ["System.IntPtr"] = typeof(IntPtr), + ["System.UIntPtr"] = typeof(UIntPtr), + + // Common reference types + ["System.Type"] = typeof(Type), + ["System.Exception"] = typeof(Exception), + ["System.Uri"] = typeof(Uri), + ["System.Version"] = typeof(Version), + + // Abstract types + ["System.Array"] = typeof(Array), + ["System.Enum"] = typeof(Enum), + ["System.ValueType"] = typeof(ValueType), + ["System.IO.Stream"] = typeof(System.IO.Stream), + + // Interfaces + ["System.IDisposable"] = typeof(IDisposable), + ["System.IComparable"] = typeof(IComparable), + ["System.ICloneable"] = typeof(ICloneable), + + // Nested types + ["System.Environment+SpecialFolder"] = typeof(Environment.SpecialFolder), + }; + + #endregion + + #region Test Data - Built-in Array Types + + /// + /// Array types derived from built-in types. + /// + public static readonly Dictionary BuiltInArrayTypes = new Dictionary + { + // Simple arrays + ["System.Int32[]"] = typeof(int[]), + ["System.String[]"] = typeof(string[]), + ["System.Boolean[]"] = typeof(bool[]), + ["System.Double[]"] = typeof(double[]), + ["System.Object[]"] = typeof(object[]), + ["System.Byte[]"] = typeof(byte[]), + ["System.DateTime[]"] = typeof(DateTime[]), + ["System.Guid[]"] = typeof(Guid[]), + + // Jagged arrays + ["System.Int32[][]"] = typeof(int[][]), + ["System.String[][]"] = typeof(string[][]), + ["System.Object[][]"] = typeof(object[][]), + + // Triple jagged arrays + ["System.Int32[][][]"] = typeof(int[][][]), + + // Multi-dimensional arrays + ["System.Int32[,]"] = typeof(int[,]), + ["System.String[,]"] = typeof(string[,]), + ["System.Object[,]"] = typeof(object[,]), + + // Multi-dimensional arrays (Rank 3) + ["System.Int32[,,]"] = typeof(int[,,]), + ["System.Double[,,]"] = typeof(double[,,]), + + // Multi-dimensional arrays (Rank 4) + ["System.Int32[,,,]"] = typeof(int[,,,]), + + // Mixed arrays (Array of 2D arrays) + // Note: C# syntax int[][,] is (int[,])[] -> System.Int32[,][] + ["System.Int32[,][]"] = typeof(int[][,]), + + // Mixed arrays (2D array of arrays) + // Note: C# syntax int[,][] is (int[])[,] -> System.Int32[][,] + ["System.Int32[][,]"] = typeof(int[,][]), + }; + + #endregion + + #region Test Data - Built-in Generic Types + + /// + /// Generic types from System.Collections.Generic. + /// + public static readonly Dictionary BuiltInGenericTypes = new Dictionary + { + // List + ["System.Collections.Generic.List"] = typeof(List), + ["System.Collections.Generic.List"] = typeof(List), + ["System.Collections.Generic.List"] = typeof(List), + ["System.Collections.Generic.List"] = typeof(List), + + // Dictionary + ["System.Collections.Generic.Dictionary"] = typeof(Dictionary), + ["System.Collections.Generic.Dictionary"] = typeof(Dictionary), + ["System.Collections.Generic.Dictionary"] = typeof(Dictionary), + ["System.Collections.Generic.Dictionary"] = typeof(Dictionary), + + // HashSet + ["System.Collections.Generic.HashSet"] = typeof(HashSet), + ["System.Collections.Generic.HashSet"] = typeof(HashSet), + + // Queue and Stack + ["System.Collections.Generic.Queue"] = typeof(Queue), + ["System.Collections.Generic.Stack"] = typeof(Stack), + + // LinkedList + ["System.Collections.Generic.LinkedList"] = typeof(LinkedList), + + // KeyValuePair + ["System.Collections.Generic.KeyValuePair"] = typeof(KeyValuePair), + + // Nullable struct (note: Nullable types are unwrapped by GetTypeId) + // ["System.Nullable"] = typeof(Nullable), // This returns "System.Int32" + + // Generic interfaces + ["System.Collections.Generic.IList"] = typeof(IList), + ["System.Collections.Generic.ICollection"] = typeof(ICollection), + ["System.Collections.Generic.IEnumerable"] = typeof(IEnumerable), + ["System.Collections.Generic.IDictionary"] = typeof(IDictionary), + ["System.Collections.Generic.ISet"] = typeof(ISet), + + // Tuple types + ["System.Tuple"] = typeof(Tuple), + ["System.Tuple"] = typeof(Tuple), + }; + + #endregion + + #region Test Data - Nested Generic Types + + /// + /// Complex nested generic types. + /// + public static readonly Dictionary NestedGenericTypes = new Dictionary + { + // List of arrays + ["System.Collections.Generic.List"] = typeof(List), + ["System.Collections.Generic.List"] = typeof(List), + + // Array of lists + ["System.Collections.Generic.List[]"] = typeof(List[]), + ["System.Collections.Generic.List[]"] = typeof(List[]), + + // List of lists + ["System.Collections.Generic.List>"] = typeof(List>), + ["System.Collections.Generic.List>"] = typeof(List>), + + // Dictionary with list value + ["System.Collections.Generic.Dictionary>"] = typeof(Dictionary>), + + // Dictionary with dictionary value + ["System.Collections.Generic.Dictionary>"] = typeof(Dictionary>), + + // List of dictionaries + ["System.Collections.Generic.List>"] = typeof(List>), + + // Triple nested generics + ["System.Collections.Generic.List>>"] = typeof(List>>), + + // Complex combinations + ["System.Collections.Generic.Dictionary>>"] = typeof(Dictionary>>), + }; + + #endregion + + #region Test Data - This Assembly Types + + /// + /// Types from ReflectorNet.Tests assembly. + /// + public static readonly Dictionary ThisAssemblyTypes = new Dictionary + { + // Simple classes + ["com.IvanMurzak.ReflectorNet.Tests.Model.Vector3"] = typeof(Vector3), + ["com.IvanMurzak.ReflectorNet.Tests.Model.SolarSystem"] = typeof(SolarSystem), + ["com.IvanMurzak.ReflectorNet.Tests.Model.GameObjectRef"] = typeof(GameObjectRef), + ["com.IvanMurzak.ReflectorNet.Tests.Model.ObjectRef"] = typeof(ObjectRef), + ["com.IvanMurzak.ReflectorNet.Tests.TestClass"] = typeof(TestClass), + + // Nested classes + ["com.IvanMurzak.ReflectorNet.Tests.Model.SolarSystem+CelestialBody"] = typeof(SolarSystem.CelestialBody), + + // Arrays of custom types + ["com.IvanMurzak.ReflectorNet.Tests.Model.Vector3[]"] = typeof(Vector3[]), + ["com.IvanMurzak.ReflectorNet.Tests.Model.GameObjectRef[]"] = typeof(GameObjectRef[]), + + // Generic with custom types + ["System.Collections.Generic.List"] = typeof(List), + ["System.Collections.Generic.List"] = typeof(List), + ["System.Collections.Generic.Dictionary"] = typeof(Dictionary), + }; + + #endregion + + #region Test Data - ReflectorNet Types + + /// + /// Types from the main ReflectorNet library. + /// + public static readonly Dictionary ReflectorNetTypes = new Dictionary + { + // Core types + ["com.IvanMurzak.ReflectorNet.Reflector"] = typeof(Reflector), + ["com.IvanMurzak.ReflectorNet.Model.SerializedMember"] = typeof(SerializedMember), + ["com.IvanMurzak.ReflectorNet.Model.SerializedMemberList"] = typeof(SerializedMemberList), + ["com.IvanMurzak.ReflectorNet.Model.MethodRef"] = typeof(MethodRef), + ["com.IvanMurzak.ReflectorNet.Model.MethodData"] = typeof(MethodData), + + // Arrays + ["com.IvanMurzak.ReflectorNet.Model.SerializedMember[]"] = typeof(SerializedMember[]), + + // Generics with ReflectorNet types + ["System.Collections.Generic.List"] = typeof(List), + ["System.Collections.Generic.Dictionary"] = typeof(Dictionary), + }; + + #endregion + + #region Test Data - Outer Assembly Types + + /// + /// Types from ReflectorNet.Tests.OuterAssembly (cross-assembly testing). + /// + public static readonly Dictionary OuterAssemblyTypes = new Dictionary + { + // Simple types + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterSimpleClass"] = typeof(OuterSimpleClass), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterSimpleStruct"] = typeof(OuterSimpleStruct), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterAbstractClass"] = typeof(OuterAbstractClass), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterSealedClass"] = typeof(OuterSealedClass), + + // Generic types (open generic definitions) + // Note: Open generic types have `N suffix in FullName + // ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterGenericClass`1"] = typeof(OuterGenericClass<>), + + // Generic types (closed/constructed) + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterGenericClass"] = typeof(OuterGenericClass), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterGenericClass"] = typeof(OuterGenericClass), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterGenericClass"] = typeof(OuterGenericClass), + + // Generic with two type parameters + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterGenericClass2"] = typeof(OuterGenericClass2), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterGenericClass2"] = typeof(OuterGenericClass2), + + // Generic with three type parameters + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterGenericClass3"] = typeof(OuterGenericClass3), + + // Generic struct + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterGenericStruct"] = typeof(OuterGenericStruct), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterGenericStruct"] = typeof(OuterGenericStruct), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterGenericStruct2"] = typeof(OuterGenericStruct2), + + // Nested types + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterContainer+NestedClass"] = typeof(OuterContainer.NestedClass), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterContainer+NestedStruct"] = typeof(OuterContainer.NestedStruct), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterContainer+NestedAbstractClass"] = typeof(OuterContainer.NestedAbstractClass), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterContainer+NestedSealedClass"] = typeof(OuterContainer.NestedSealedClass), + + // Nested generic types + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterContainer+NestedGenericClass"] = typeof(OuterContainer.NestedGenericClass), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterContainer+NestedGenericStruct"] = typeof(OuterContainer.NestedGenericStruct), + + // Double nested types + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterContainer+NestedContainer+DoubleNestedClass"] = typeof(OuterContainer.NestedContainer.DoubleNestedClass), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterContainer+NestedContainer+DoubleNestedStruct"] = typeof(OuterContainer.NestedContainer.DoubleNestedStruct), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterContainer+NestedContainer+DoubleNestedGenericClass"] = typeof(OuterContainer.NestedContainer.DoubleNestedGenericClass), + + // Generic container with nested types + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterGenericContainer+NestedInGeneric"] = typeof(OuterGenericContainer.NestedInGeneric), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterGenericContainer+NestedStructInGeneric"] = typeof(OuterGenericContainer.NestedStructInGeneric), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterGenericContainer+NestedGenericInGeneric"] = typeof(OuterGenericContainer.NestedGenericInGeneric), + + // Interfaces + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.IOuterInterface"] = typeof(IOuterInterface), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.IOuterGenericInterface"] = typeof(IOuterGenericInterface), + + // Enums + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterEnum"] = typeof(OuterEnum), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterFlagsEnum"] = typeof(OuterFlagsEnum), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterEnumContainer+NestedEnum"] = typeof(OuterEnumContainer.NestedEnum), + + // Existing types from OuterAssembly + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.Person"] = typeof(Person), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.Address"] = typeof(Address), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.Company"] = typeof(Company), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.ParentClass"] = typeof(ParentClass), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.ParentClass+NestedClass"] = typeof(ParentClass.NestedClass), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.ParentClass+NestedStaticClass"] = typeof(ParentClass.NestedStaticClass), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.StaticParentClass+NestedClass"] = typeof(StaticParentClass.NestedClass), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.StaticParentClass+NestedStaticClass"] = typeof(StaticParentClass.NestedStaticClass), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.WrapperClass"] = typeof(WrapperClass), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.WrapperClass"] = typeof(WrapperClass), + }; + + #endregion + + #region Test Data - Outer Assembly Array Types + + /// + /// Array types from OuterAssembly. + /// + public static readonly Dictionary OuterAssemblyArrayTypes = new Dictionary + { + // Simple arrays + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterSimpleClass[]"] = typeof(OuterSimpleClass[]), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterSimpleStruct[]"] = typeof(OuterSimpleStruct[]), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterEnum[]"] = typeof(OuterEnum[]), + + // Jagged arrays + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterSimpleClass[][]"] = typeof(OuterSimpleClass[][]), + + // Generic arrays + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterGenericClass[]"] = typeof(OuterGenericClass[]), + + // Nested type arrays + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterContainer+NestedClass[]"] = typeof(OuterContainer.NestedClass[]), + }; + + #endregion + + #region Test Data - Complex Combined Types + + /// + /// Complex combinations of generics, arrays, and nested types. + /// + public static readonly Dictionary ComplexCombinedTypes = new Dictionary + { + // Generic with outer assembly type + ["System.Collections.Generic.List"] = typeof(List), + ["System.Collections.Generic.Dictionary"] = typeof(Dictionary), + + // Generic with nested type + ["System.Collections.Generic.List"] = typeof(List), + + // Dictionary with two custom types + ["System.Collections.Generic.Dictionary"] = typeof(Dictionary), + + // Nested generic with outer assembly types + ["System.Collections.Generic.List>"] = typeof(List>), + + // Generic with generic type argument from outer assembly + ["System.Collections.Generic.List>"] = typeof(List>), + + // Array of generic outer assembly type + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterGenericClass[]"] = typeof(OuterGenericClass[]), + + // Generic with array type argument + ["System.Collections.Generic.List"] = typeof(List), + + // Dictionary with array value type + ["System.Collections.Generic.Dictionary"] = typeof(Dictionary), + + // Cross-assembly generic combinations + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterGenericClass"] = typeof(OuterGenericClass), + ["com.IvanMurzak.ReflectorNet.OuterAssembly.Model.OuterGenericClass2"] = typeof(OuterGenericClass2), + }; + + #endregion + + #region Test Methods + + [Fact] + public void GetTypeId_BuiltInTypes() + { + ValidateTypeIdDictionary(BuiltInTypes, nameof(BuiltInTypes)); + } + + [Fact] + public void GetTypeId_BuiltInArrayTypes() + { + ValidateTypeIdDictionary(BuiltInArrayTypes, nameof(BuiltInArrayTypes)); + } + + [Fact] + public void GetTypeId_BuiltInGenericTypes() + { + ValidateTypeIdDictionary(BuiltInGenericTypes, nameof(BuiltInGenericTypes)); + } + + [Fact] + public void GetTypeId_NestedGenericTypes() + { + ValidateTypeIdDictionary(NestedGenericTypes, nameof(NestedGenericTypes)); + } + + [Fact] + public void GetTypeId_ThisAssemblyTypes() + { + ValidateTypeIdDictionary(ThisAssemblyTypes, nameof(ThisAssemblyTypes)); + } + + [Fact] + public void GetTypeId_ReflectorNetTypes() + { + ValidateTypeIdDictionary(ReflectorNetTypes, nameof(ReflectorNetTypes)); + } + + [Fact] + public void GetTypeId_OuterAssemblyTypes() + { + ValidateTypeIdDictionary(OuterAssemblyTypes, nameof(OuterAssemblyTypes)); + } + + [Fact] + public void GetTypeId_OuterAssemblyArrayTypes() + { + ValidateTypeIdDictionary(OuterAssemblyArrayTypes, nameof(OuterAssemblyArrayTypes)); + } + + [Fact] + public void GetTypeId_ComplexCombinedTypes() + { + ValidateTypeIdDictionary(ComplexCombinedTypes, nameof(ComplexCombinedTypes)); + } + + /// + /// Validates all entries in a dictionary mapping expected type IDs to types. + /// + private void ValidateTypeIdDictionary(Dictionary typeMap, string dictionaryName) + { + _output.WriteLine($"### Validating {dictionaryName} ({typeMap.Count} entries)\n"); + + var failedTypes = new List<(string expected, string actual, Type type)>(); + var passedCount = 0; + + foreach (var kvp in typeMap) + { + var expectedTypeId = kvp.Key; + var type = kvp.Value; + var actualTypeId = TypeUtils.GetTypeId(type); + + if (expectedTypeId == actualTypeId) + { + passedCount++; + _output.WriteLine($" [PASS] {expectedTypeId}"); + } + else + { + failedTypes.Add((expectedTypeId, actualTypeId, type)); + _output.WriteLine($" [FAIL] Expected: {expectedTypeId}"); + _output.WriteLine($" Actual: {actualTypeId}"); + _output.WriteLine($" Type: {type}"); + } + } + + _output.WriteLine($"\n### Summary: {passedCount}/{typeMap.Count} passed\n"); + + if (failedTypes.Count > 0) + { + var errorMessage = $"Failed {failedTypes.Count} type(s) in {dictionaryName}:\n"; + foreach (var (expected, actual, type) in failedTypes) + { + errorMessage += $" - Expected '{expected}' but got '{actual}' for type {type}\n"; + } + Assert.Fail(errorMessage); + } + } + + #endregion + } +} diff --git a/ReflectorNet.Tests/src/TypeUtilsTests/GetTypeShortNameTests.cs b/ReflectorNet.Tests/src/TypeUtilsTests/GetTypeShortNameTests.cs new file mode 100644 index 00000000..17c585f9 --- /dev/null +++ b/ReflectorNet.Tests/src/TypeUtilsTests/GetTypeShortNameTests.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Text; +using com.IvanMurzak.ReflectorNet.Utils; +using Xunit; +using Xunit.Abstractions; + +namespace com.IvanMurzak.ReflectorNet.Tests.TypeUtilsTests +{ + public class GetTypeShortNameTests : BaseTest + { + public GetTypeShortNameTests(ITestOutputHelper output) : base(output) { } + + [Fact] + public void GetTypeShortName_BuiltInTypes() + { + ValidateTypeShortName(GetTypeIdTests.BuiltInTypes); + } + + [Fact] + public void GetTypeShortName_BuiltInArrayTypes() + { + ValidateTypeShortName(GetTypeIdTests.BuiltInArrayTypes); + } + + [Fact] + public void GetTypeShortName_BuiltInGenericTypes() + { + ValidateTypeShortName(GetTypeIdTests.BuiltInGenericTypes); + } + + [Fact] + public void GetTypeShortName_NestedGenericTypes() + { + ValidateTypeShortName(GetTypeIdTests.NestedGenericTypes); + } + + [Fact] + public void GetTypeShortName_ThisAssemblyTypes() + { + ValidateTypeShortName(GetTypeIdTests.ThisAssemblyTypes); + } + + [Fact] + public void GetTypeShortName_ReflectorNetTypes() + { + ValidateTypeShortName(GetTypeIdTests.ReflectorNetTypes); + } + + [Fact] + public void GetTypeShortName_OuterAssemblyTypes() + { + ValidateTypeShortName(GetTypeIdTests.OuterAssemblyTypes); + } + + private void ValidateTypeShortName(Dictionary typeMap) + { + var failed = new List(); + foreach (var kvp in typeMap) + { + var typeId = kvp.Key; + var type = kvp.Value; + + var expectedShortName = StripNamespace(typeId); + var actualShortName = TypeUtils.GetTypeShortName(type); + + // Normalize spaces in expectedShortName just in case + // expectedShortName = expectedShortName.Replace(", ", ","); + // No, GetTypeShortName outputs ", ". My StripNamespace outputs ", ". + + if (expectedShortName != actualShortName) + { + _output.WriteLine($"FAIL: {typeId}"); + _output.WriteLine($" Expected: {expectedShortName}"); + _output.WriteLine($" Actual: {actualShortName}"); + failed.Add(typeId); + } + else + { + _output.WriteLine($"PASS: {typeId} -> {actualShortName}"); + } + } + + if (failed.Count > 0) + { + Assert.Fail($"Failed {failed.Count} types. See output for details."); + } + } + + private string StripNamespace(string typeId) + { + if (string.IsNullOrEmpty(typeId)) return typeId; + + var sb = new StringBuilder(); + var currentToken = new StringBuilder(); + + for (int i = 0; i < typeId.Length; i++) + { + char c = typeId[i]; + if (char.IsLetterOrDigit(c) || c == '.' || c == '_' || c == '`') + { + currentToken.Append(c); + } + else + { + // Flush current token + if (currentToken.Length > 0) + { + var token = currentToken.ToString(); + var shortToken = GetShortToken(token); + sb.Append(shortToken); + currentToken.Clear(); + } + + sb.Append(c); + if (c == ',') + { + sb.Append(" "); + } + } + } + + // Flush last token + if (currentToken.Length > 0) + { + var token = currentToken.ToString(); + var shortToken = GetShortToken(token); + sb.Append(shortToken); + } + + return sb.ToString(); + } + + private string GetShortToken(string token) + { + var lastDot = token.LastIndexOf('.'); + if (lastDot >= 0) + { + return token.Substring(lastDot + 1); + } + return token; + } + } +} diff --git a/ReflectorNet.Tests/src/TypeUtilsTests/GetTypeTests.cs b/ReflectorNet.Tests/src/TypeUtilsTests/GetTypeTests.cs new file mode 100644 index 00000000..73a86233 --- /dev/null +++ b/ReflectorNet.Tests/src/TypeUtilsTests/GetTypeTests.cs @@ -0,0 +1,170 @@ +/* + * ReflectorNet + * Author: Ivan Murzak (https://github.com/IvanMurzak) + * Copyright (c) 2025 Ivan Murzak + * Licensed under the Apache License, Version 2.0. See LICENSE file in the project root for full license information. + */ + +using System; +using System.Collections.Generic; +using com.IvanMurzak.ReflectorNet.Utils; +using Xunit; +using Xunit.Abstractions; + +namespace com.IvanMurzak.ReflectorNet.Tests.TypeUtilsTests +{ + /// + /// Tests for TypeUtils.GetType() method. + /// Verifies that type ID strings are correctly resolved back to their Type objects. + /// Uses the same dictionaries as GetTypeIdTests but tests in reverse direction (string → Type). + /// + public class GetTypeTests : BaseTest + { + public GetTypeTests(ITestOutputHelper output) : base(output) { } + + #region Test Methods + + [Fact] + public void GetType_BuiltInTypes() + { + ValidateGetTypeDictionary(GetTypeIdTests.BuiltInTypes, nameof(GetTypeIdTests.BuiltInTypes)); + } + + [Fact] + public void GetType_BuiltInArrayTypes() + { + ValidateGetTypeDictionary(GetTypeIdTests.BuiltInArrayTypes, nameof(GetTypeIdTests.BuiltInArrayTypes)); + } + + [Fact] + public void GetType_BuiltInGenericTypes() + { + ValidateGetTypeDictionary(GetTypeIdTests.BuiltInGenericTypes, nameof(GetTypeIdTests.BuiltInGenericTypes)); + } + + [Fact] + public void GetType_NestedGenericTypes() + { + ValidateGetTypeDictionary(GetTypeIdTests.NestedGenericTypes, nameof(GetTypeIdTests.NestedGenericTypes)); + } + + [Fact] + public void GetType_ThisAssemblyTypes() + { + ValidateGetTypeDictionary(GetTypeIdTests.ThisAssemblyTypes, nameof(GetTypeIdTests.ThisAssemblyTypes)); + } + + [Fact] + public void GetType_ReflectorNetTypes() + { + ValidateGetTypeDictionary(GetTypeIdTests.ReflectorNetTypes, nameof(GetTypeIdTests.ReflectorNetTypes)); + } + + [Fact] + public void GetType_OuterAssemblyTypes() + { + ValidateGetTypeDictionary(GetTypeIdTests.OuterAssemblyTypes, nameof(GetTypeIdTests.OuterAssemblyTypes)); + } + + [Fact] + public void GetType_OuterAssemblyArrayTypes() + { + ValidateGetTypeDictionary(GetTypeIdTests.OuterAssemblyArrayTypes, nameof(GetTypeIdTests.OuterAssemblyArrayTypes)); + } + + [Fact] + public void GetType_ComplexCombinedTypes() + { + ValidateGetTypeDictionary(GetTypeIdTests.ComplexCombinedTypes, nameof(GetTypeIdTests.ComplexCombinedTypes)); + } + + /// + /// Validates all entries in a dictionary by resolving type ID strings back to types. + /// + private void ValidateGetTypeDictionary(Dictionary typeMap, string dictionaryName) + { + _output.WriteLine($"### Validating {dictionaryName} ({typeMap.Count} entries)\n"); + + var failedTypes = new List<(string typeId, Type? expected, Type? actual)>(); + var passedCount = 0; + + foreach (var kvp in typeMap) + { + var typeId = kvp.Key; + var expectedType = kvp.Value; + var actualType = TypeUtils.GetType(typeId); + + if (actualType == expectedType) + { + passedCount++; + _output.WriteLine($" [PASS] {typeId} → {actualType?.FullName ?? "null"}"); + } + else + { + failedTypes.Add((typeId, expectedType, actualType)); + _output.WriteLine($" [FAIL] TypeId: {typeId}"); + _output.WriteLine($" Expected: {expectedType?.FullName ?? "null"}"); + _output.WriteLine($" Actual: {actualType?.FullName ?? "null"}"); + } + } + + _output.WriteLine($"\n### Summary: {passedCount}/{typeMap.Count} passed\n"); + + if (failedTypes.Count > 0) + { + var errorMessage = $"Failed {failedTypes.Count} type(s) in {dictionaryName}:\n"; + foreach (var (typeId, expected, actual) in failedTypes) + { + errorMessage += $" - TypeId '{typeId}': expected '{expected?.FullName ?? "null"}' but got '{actual?.FullName ?? "null"}'\n"; + } + Assert.Fail(errorMessage); + } + } + + #endregion + + #region Edge Case Tests + + [Fact] + public void GetType_NullOrEmpty_ReturnsNull() + { + Assert.Null(TypeUtils.GetType(null)); + Assert.Null(TypeUtils.GetType("")); + Assert.Null(TypeUtils.GetType(" ")); + } + + [Fact] + public void GetType_InvalidTypeName_ReturnsNull() + { + Assert.Null(TypeUtils.GetType("NonExistent.Type.That.Does.Not.Exist")); + Assert.Null(TypeUtils.GetType("System.NonExistentType")); + Assert.Null(TypeUtils.GetType("InvalidGeneric<>")); + } + + [Fact] + public void GetType_RoundTrip_GetTypeId_GetType() + { + // Verify round-trip: Type → GetTypeId → GetType → same Type + var testTypes = new[] + { + typeof(int), + typeof(string), + typeof(List), + typeof(Dictionary), + typeof(int[]), + typeof(List>), + }; + + foreach (var originalType in testTypes) + { + var typeId = TypeUtils.GetTypeId(originalType); + var resolvedType = TypeUtils.GetType(typeId); + + _output.WriteLine($" {originalType} → \"{typeId}\" → {resolvedType}"); + Assert.Equal(originalType, resolvedType); + } + } + + #endregion + } +} diff --git a/ReflectorNet/src/Converter/Json/BoolJsonConverter.cs b/ReflectorNet/src/Converter/Json/BoolJsonConverter.cs index 400078ed..26bc469e 100644 --- a/ReflectorNet/src/Converter/Json/BoolJsonConverter.cs +++ b/ReflectorNet/src/Converter/Json/BoolJsonConverter.cs @@ -31,7 +31,7 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null to non-nullable type '{typeToConvert.GetTypeId()}'."); } // Handle direct boolean tokens @@ -54,16 +54,16 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null string to non-nullable type {typeToConvert.GetTypeName(pretty: true)}.\nInput value: null"); + throw new JsonException($"Cannot convert null string to non-nullable type '{typeToConvert.GetTypeId()}'.\nInput value: null"); } if (bool.TryParse(stringValue, out var boolResult)) return boolResult; - throw new JsonException($"Unable to convert '{stringValue}' to {typeof(bool).GetTypeName(pretty: true)}.\nInput value: {stringValue}"); + throw new JsonException($"Unable to convert '{stringValue}' to '{typeof(bool).GetTypeId()}'.\nInput value: {stringValue}"); } - throw new JsonException($"Expected string, boolean, or number token but got {reader.TokenType} for type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Expected string, boolean, or number token but got {reader.TokenType} for type '{typeToConvert.GetTypeId()}'."); } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) diff --git a/ReflectorNet/src/Converter/Json/ByteJsonConverter.cs b/ReflectorNet/src/Converter/Json/ByteJsonConverter.cs index 961846b4..c5254792 100644 --- a/ReflectorNet/src/Converter/Json/ByteJsonConverter.cs +++ b/ReflectorNet/src/Converter/Json/ByteJsonConverter.cs @@ -32,7 +32,7 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null to non-nullable type '{typeToConvert.GetTypeId()}'."); } // Handle direct number tokens @@ -51,13 +51,13 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null string to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null string to non-nullable type '{typeToConvert.GetTypeId()}'."); } return ParseByte(stringValue); } - throw new JsonException($"Expected string or number token but got {reader.TokenType} for type {typeToConvert.GetTypeName(pretty: true)}"); + throw new JsonException($"Expected string or number token but got {reader.TokenType} for type '{typeToConvert.GetTypeId()}'"); } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) @@ -69,14 +69,14 @@ private static byte ParseByte(string stringValue) { if (byte.TryParse(stringValue, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) return result; - throw new JsonException($"Unable to convert '{stringValue}' to {typeof(byte).GetTypeName(pretty: true)}."); + throw new JsonException($"Unable to convert '{stringValue}' to {typeof(byte).GetTypeId()}."); } private static byte ConvertToByte(double value) { if (value >= byte.MinValue && value <= byte.MaxValue && value == Math.Floor(value)) return (byte)value; - throw new JsonException($"Value {value} is out of range for {typeof(byte).GetTypeName(pretty: true)}."); + throw new JsonException($"Value {value} is out of range for {typeof(byte).GetTypeId()}."); } } } \ No newline at end of file diff --git a/ReflectorNet/src/Converter/Json/DateTimeJsonConverter.cs b/ReflectorNet/src/Converter/Json/DateTimeJsonConverter.cs index 4563ca2b..64c13866 100644 --- a/ReflectorNet/src/Converter/Json/DateTimeJsonConverter.cs +++ b/ReflectorNet/src/Converter/Json/DateTimeJsonConverter.cs @@ -33,7 +33,7 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null to non-nullable type '{typeToConvert.GetTypeId()}'."); } // Handle numeric timestamps (Unix time in milliseconds) @@ -52,16 +52,16 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null string to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null string to non-nullable type '{typeToConvert.GetTypeId()}'."); } if (DateTime.TryParse(stringValue, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var dateTimeResult)) return dateTimeResult; - throw new JsonException($"Unable to convert '{stringValue}' to {typeof(DateTime).GetTypeName(pretty: true)}."); + throw new JsonException($"Unable to convert '{stringValue}' to {typeof(DateTime).GetTypeId()}."); } - throw new JsonException($"Expected string or number token but got {reader.TokenType} for type {typeToConvert.GetTypeName(pretty: true)}"); + throw new JsonException($"Expected string or number token but got {reader.TokenType} for type '{typeToConvert.GetTypeId()}'"); } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) diff --git a/ReflectorNet/src/Converter/Json/DateTimeOffsetJsonConverter.cs b/ReflectorNet/src/Converter/Json/DateTimeOffsetJsonConverter.cs index 2022dacb..b8fe4d91 100644 --- a/ReflectorNet/src/Converter/Json/DateTimeOffsetJsonConverter.cs +++ b/ReflectorNet/src/Converter/Json/DateTimeOffsetJsonConverter.cs @@ -33,7 +33,7 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null to non-nullable type '{typeToConvert.GetTypeId()}'."); } // Handle numeric timestamps (Unix time in milliseconds) @@ -52,16 +52,16 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null string to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null string to non-nullable type '{typeToConvert.GetTypeId()}'."); } if (DateTimeOffset.TryParse(stringValue, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var dateTimeOffsetResult)) return dateTimeOffsetResult; - throw new JsonException($"Unable to convert '{stringValue}' to {typeof(DateTimeOffset).GetTypeName(pretty: true)}."); + throw new JsonException($"Unable to convert '{stringValue}' to {typeof(DateTimeOffset).GetTypeId()}."); } - throw new JsonException($"Expected string or number token but got {reader.TokenType} for type {typeToConvert.GetTypeName(pretty: true)}"); + throw new JsonException($"Expected string or number token but got {reader.TokenType} for type '{typeToConvert.GetTypeId()}'"); } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) diff --git a/ReflectorNet/src/Converter/Json/DecimalJsonConverter.cs b/ReflectorNet/src/Converter/Json/DecimalJsonConverter.cs index 28d0a0ca..58ce3383 100644 --- a/ReflectorNet/src/Converter/Json/DecimalJsonConverter.cs +++ b/ReflectorNet/src/Converter/Json/DecimalJsonConverter.cs @@ -32,7 +32,7 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null to non-nullable type '{typeToConvert.GetTypeId()}'."); } // Handle direct number tokens @@ -50,16 +50,16 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null string to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null string to non-nullable type '{typeToConvert.GetTypeId()}'."); } if (decimal.TryParse(stringValue, NumberStyles.Number, CultureInfo.InvariantCulture, out var decimalResult)) return decimalResult; - throw new JsonException($"Unable to convert '{stringValue}' to {typeof(decimal).GetTypeName(pretty: true)}."); + throw new JsonException($"Unable to convert '{stringValue}' to {typeof(decimal).GetTypeId()}."); } - throw new JsonException($"Expected string or number token but got {reader.TokenType} for type {typeToConvert.GetTypeName(pretty: true)}"); + throw new JsonException($"Expected string or number token but got {reader.TokenType} for type '{typeToConvert.GetTypeId()}'"); } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) diff --git a/ReflectorNet/src/Converter/Json/DoubleJsonConverter.cs b/ReflectorNet/src/Converter/Json/DoubleJsonConverter.cs index 849e2b41..8ca91a0d 100644 --- a/ReflectorNet/src/Converter/Json/DoubleJsonConverter.cs +++ b/ReflectorNet/src/Converter/Json/DoubleJsonConverter.cs @@ -32,7 +32,7 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null to non-nullable type '{typeToConvert.GetTypeId()}'."); } // Handle direct number tokens @@ -50,13 +50,13 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null string to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null string to non-nullable type '{typeToConvert.GetTypeId()}'."); } return ParseDouble(stringValue); } - throw new JsonException($"Expected string or number token but got {reader.TokenType} for type {typeToConvert.GetTypeName(pretty: true)}"); + throw new JsonException($"Expected string or number token but got {reader.TokenType} for type '{typeToConvert.GetTypeId()}'"); } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) @@ -68,7 +68,7 @@ private static double ParseDouble(string stringValue) { if (double.TryParse(stringValue, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) return result; - throw new JsonException($"Unable to convert '{stringValue}' to {typeof(double).GetTypeName(pretty: true)}."); + throw new JsonException($"Unable to convert '{stringValue}' to {typeof(double).GetTypeId()}."); } } } \ No newline at end of file diff --git a/ReflectorNet/src/Converter/Json/EnumJsonConverter.cs b/ReflectorNet/src/Converter/Json/EnumJsonConverter.cs index c23daf2c..2e095478 100644 --- a/ReflectorNet/src/Converter/Json/EnumJsonConverter.cs +++ b/ReflectorNet/src/Converter/Json/EnumJsonConverter.cs @@ -31,7 +31,7 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null to non-nullable type '{typeToConvert.GetTypeId()}'."); } var underlyingType = Nullable.GetUnderlyingType(typeToConvert) ?? typeToConvert; @@ -57,7 +57,7 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null string to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null string to non-nullable type '{typeToConvert.GetTypeId()}'."); } if (!Enum.TryParse(underlyingType, stringValue, ignoreCase: true, out var enumValue)) @@ -69,7 +69,7 @@ public override bool CanConvert(Type typeToConvert) throw new JsonException($"Unable to convert '{stringValue}' to enum {underlyingType.Name}. Valid values are: {string.Join(", ", Enum.GetNames(underlyingType))}"); } - throw new JsonException($"Expected string or number token but got {reader.TokenType} for enum type {typeToConvert.GetTypeName(pretty: true)}"); + throw new JsonException($"Expected string or number token but got {reader.TokenType} for enum type '{typeToConvert.GetTypeId()}'"); } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) diff --git a/ReflectorNet/src/Converter/Json/GuidJsonConverter.cs b/ReflectorNet/src/Converter/Json/GuidJsonConverter.cs index 56960595..8d103678 100644 --- a/ReflectorNet/src/Converter/Json/GuidJsonConverter.cs +++ b/ReflectorNet/src/Converter/Json/GuidJsonConverter.cs @@ -31,7 +31,7 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null to non-nullable type '{typeToConvert.GetTypeId()}'."); } // Handle string tokens @@ -43,16 +43,16 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null string to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null string to non-nullable type '{typeToConvert.GetTypeId()}'."); } if (Guid.TryParse(stringValue, out var guidResult)) return guidResult; - throw new JsonException($"Unable to convert '{stringValue}' to {typeof(Guid).GetTypeName(pretty: true)}."); + throw new JsonException($"Unable to convert '{stringValue}' to {typeof(Guid).GetTypeId()}."); } - throw new JsonException($"Expected string token but got {reader.TokenType} for type {typeToConvert.GetTypeName(pretty: true)}"); + throw new JsonException($"Expected string token but got {reader.TokenType} for type '{typeToConvert.GetTypeId()}'"); } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) diff --git a/ReflectorNet/src/Converter/Json/Int16JsonConverter.cs b/ReflectorNet/src/Converter/Json/Int16JsonConverter.cs index 1de06e24..c95da9e3 100644 --- a/ReflectorNet/src/Converter/Json/Int16JsonConverter.cs +++ b/ReflectorNet/src/Converter/Json/Int16JsonConverter.cs @@ -32,7 +32,7 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null to non-nullable type '{typeToConvert.GetTypeId()}'."); } // Handle direct number tokens @@ -51,13 +51,13 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null string to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null string to non-nullable type '{typeToConvert.GetTypeId()}'."); } return ParseInt16(stringValue); } - throw new JsonException($"Expected string or number token but got {reader.TokenType} for type {typeToConvert.GetTypeName(pretty: true)}"); + throw new JsonException($"Expected string or number token but got {reader.TokenType} for type '{typeToConvert.GetTypeId()}'"); } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) @@ -69,14 +69,14 @@ private static short ParseInt16(string stringValue) { if (short.TryParse(stringValue, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) return result; - throw new JsonException($"Unable to convert '{stringValue}' to {typeof(short).GetTypeName(pretty: true)}."); + throw new JsonException($"Unable to convert '{stringValue}' to {typeof(short).GetTypeId()}."); } private static short ConvertToInt16(double value) { if (value >= short.MinValue && value <= short.MaxValue && value == Math.Floor(value)) return (short)value; - throw new JsonException($"Value {value} is out of range for {typeof(short).GetTypeName(pretty: true)}."); + throw new JsonException($"Value {value} is out of range for {typeof(short).GetTypeId()}."); } } } \ No newline at end of file diff --git a/ReflectorNet/src/Converter/Json/Int32JsonConverter.cs b/ReflectorNet/src/Converter/Json/Int32JsonConverter.cs index af5418e4..79f1c34a 100644 --- a/ReflectorNet/src/Converter/Json/Int32JsonConverter.cs +++ b/ReflectorNet/src/Converter/Json/Int32JsonConverter.cs @@ -32,7 +32,7 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null to non-nullable type '{typeToConvert.GetTypeId()}'."); } // Handle direct number tokens @@ -51,13 +51,13 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null string to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null string to non-nullable type '{typeToConvert.GetTypeId()}'."); } return ParseInt32(stringValue); } - throw new JsonException($"Expected string or number token but got {reader.TokenType} for type {typeToConvert.GetTypeName(pretty: true)}"); + throw new JsonException($"Expected string or number token but got {reader.TokenType} for type '{typeToConvert.GetTypeId()}'"); } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) @@ -69,14 +69,14 @@ private static int ParseInt32(string stringValue) { if (int.TryParse(stringValue, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) return result; - throw new JsonException($"Unable to convert '{stringValue}' to {typeof(int).GetTypeName(pretty: true)}."); + throw new JsonException($"Unable to convert '{stringValue}' to {typeof(int).GetTypeId()}."); } private static int ConvertToInt32(double value) { if (value >= int.MinValue && value <= int.MaxValue && value == Math.Floor(value)) return (int)value; - throw new JsonException($"Value {value} is out of range for {typeof(int).GetTypeName(pretty: true)}."); + throw new JsonException($"Value {value} is out of range for {typeof(int).GetTypeId()}."); } } } \ No newline at end of file diff --git a/ReflectorNet/src/Converter/Json/Int64JsonConverter.cs b/ReflectorNet/src/Converter/Json/Int64JsonConverter.cs index b54a0f97..eb7338d6 100644 --- a/ReflectorNet/src/Converter/Json/Int64JsonConverter.cs +++ b/ReflectorNet/src/Converter/Json/Int64JsonConverter.cs @@ -32,7 +32,7 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null to non-nullable type '{typeToConvert.GetTypeId()}'."); } // Handle direct number tokens @@ -51,13 +51,13 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null string to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null string to non-nullable type '{typeToConvert.GetTypeId()}'."); } return ParseInt64(stringValue); } - throw new JsonException($"Expected string or number token but got {reader.TokenType} for type {typeToConvert.GetTypeName(pretty: true)}"); + throw new JsonException($"Expected string or number token but got {reader.TokenType} for type '{typeToConvert.GetTypeId()}'"); } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) @@ -69,14 +69,14 @@ private static long ParseInt64(string stringValue) { if (long.TryParse(stringValue, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) return result; - throw new JsonException($"Unable to convert '{stringValue}' to {typeof(long).GetTypeName(pretty: true)}."); + throw new JsonException($"Unable to convert '{stringValue}' to {typeof(long).GetTypeId()}."); } private static long ConvertToInt64(double value) { if (value >= long.MinValue && value <= long.MaxValue && value == Math.Floor(value)) return (long)value; - throw new JsonException($"Value {value} is out of range for {typeof(long).GetTypeName(pretty: true)}."); + throw new JsonException($"Value {value} is out of range for {typeof(long).GetTypeId()}."); } } } \ No newline at end of file diff --git a/ReflectorNet/src/Converter/Json/JsonNodeJsonConverter.cs b/ReflectorNet/src/Converter/Json/JsonNodeJsonConverter.cs index 9b1e8d9c..e2b816d5 100644 --- a/ReflectorNet/src/Converter/Json/JsonNodeJsonConverter.cs +++ b/ReflectorNet/src/Converter/Json/JsonNodeJsonConverter.cs @@ -27,7 +27,7 @@ public abstract class JsonNodeJsonConverter : JsonSchemaConverter, IJsonSc if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null to non-nullable type '{typeToConvert.GetTypeId()}'."); } if (reader.TokenType is JsonTokenType.StartObject or JsonTokenType.StartArray) @@ -38,7 +38,7 @@ public abstract class JsonNodeJsonConverter : JsonSchemaConverter, IJsonSc return CreateJsonNode(clonedElement); } - throw new JsonException($"Expected Null, StartObject or StartArray token but got {reader.TokenType} for type {typeToConvert.GetTypeName(pretty: true)}"); + throw new JsonException($"Expected Null, StartObject or StartArray token but got {reader.TokenType} for type '{typeToConvert.GetTypeId()}'"); } public override void Write(Utf8JsonWriter writer, T? value, JsonSerializerOptions options) diff --git a/ReflectorNet/src/Converter/Json/MethodInfoConverter.cs b/ReflectorNet/src/Converter/Json/MethodInfoConverter.cs index d578c0f8..80e11a3b 100644 --- a/ReflectorNet/src/Converter/Json/MethodInfoConverter.cs +++ b/ReflectorNet/src/Converter/Json/MethodInfoConverter.cs @@ -60,7 +60,7 @@ public override void Write(Utf8JsonWriter writer, MethodInfo value, JsonSerializ { writer.WriteStartObject(); writer.WriteString(Json.Name, value.Name); - writer.WriteString(Json.DeclaringType, value.DeclaringType?.GetTypeName(pretty: false)); + writer.WriteString(Json.DeclaringType, value.DeclaringType?.GetTypeId()); writer.WritePropertyName(Json.Parameters); writer.WriteStartArray(); @@ -68,7 +68,7 @@ public override void Write(Utf8JsonWriter writer, MethodInfo value, JsonSerializ { writer.WriteStartObject(); writer.WriteString(Json.Name, param.Name); - writer.WriteString(Json.Type, param.ParameterType.GetTypeName(pretty: false)); + writer.WriteString(Json.Type, param.ParameterType.GetTypeId()); writer.WriteEndObject(); } writer.WriteEndArray(); diff --git a/ReflectorNet/src/Converter/Json/SByteJsonConverter.cs b/ReflectorNet/src/Converter/Json/SByteJsonConverter.cs index 4f803741..8f2258f9 100644 --- a/ReflectorNet/src/Converter/Json/SByteJsonConverter.cs +++ b/ReflectorNet/src/Converter/Json/SByteJsonConverter.cs @@ -32,7 +32,7 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null to non-nullable type '{typeToConvert.GetTypeId()}'."); } // Handle direct number tokens @@ -51,13 +51,13 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null string to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null string to non-nullable type '{typeToConvert.GetTypeId()}'."); } return ParseSByte(stringValue); } - throw new JsonException($"Expected string or number token but got {reader.TokenType} for type {typeToConvert.GetTypeName(pretty: true)}"); + throw new JsonException($"Expected string or number token but got {reader.TokenType} for type '{typeToConvert.GetTypeId()}'"); } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) @@ -69,14 +69,14 @@ private static sbyte ParseSByte(string stringValue) { if (sbyte.TryParse(stringValue, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) return result; - throw new JsonException($"Unable to convert '{stringValue}' to {typeof(sbyte).GetTypeName(pretty: true)}."); + throw new JsonException($"Unable to convert '{stringValue}' to {typeof(sbyte).GetTypeId()}."); } private static sbyte ConvertToSByte(double value) { if (value >= sbyte.MinValue && value <= sbyte.MaxValue && value == Math.Floor(value)) return (sbyte)value; - throw new JsonException($"Value {value} is out of range for {typeof(sbyte).GetTypeName(pretty: true)}."); + throw new JsonException($"Value {value} is out of range for {typeof(sbyte).GetTypeId()}."); } } } \ No newline at end of file diff --git a/ReflectorNet/src/Converter/Json/SingleJsonConverter.cs b/ReflectorNet/src/Converter/Json/SingleJsonConverter.cs index a0d93fc4..24af8cc4 100644 --- a/ReflectorNet/src/Converter/Json/SingleJsonConverter.cs +++ b/ReflectorNet/src/Converter/Json/SingleJsonConverter.cs @@ -32,7 +32,7 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null to non-nullable type '{typeToConvert.GetTypeId()}'."); } // Handle direct number tokens @@ -51,13 +51,13 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null string to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null string to non-nullable type '{typeToConvert.GetTypeId()}'."); } return ParseSingle(stringValue); } - throw new JsonException($"Expected string or number token but got {reader.TokenType} for type {typeToConvert.GetTypeName(pretty: true)}"); + throw new JsonException($"Expected string or number token but got {reader.TokenType} for type '{typeToConvert.GetTypeId()}'"); } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) @@ -69,14 +69,14 @@ private static float ParseSingle(string stringValue) { if (float.TryParse(stringValue, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) return result; - throw new JsonException($"Unable to convert '{stringValue}' to {typeof(float).GetTypeName(pretty: true)}."); + throw new JsonException($"Unable to convert '{stringValue}' to {typeof(float).GetTypeId()}."); } private static float ConvertToFloat(double value) { if (value >= float.MinValue && value <= float.MaxValue) return (float)value; - throw new JsonException($"Value {value} is out of range for {typeof(float).GetTypeName(pretty: true)}."); + throw new JsonException($"Value {value} is out of range for {typeof(float).GetTypeId()}."); } } } \ No newline at end of file diff --git a/ReflectorNet/src/Converter/Json/TimeSpanJsonConverter.cs b/ReflectorNet/src/Converter/Json/TimeSpanJsonConverter.cs index 58fabae1..cf3a5084 100644 --- a/ReflectorNet/src/Converter/Json/TimeSpanJsonConverter.cs +++ b/ReflectorNet/src/Converter/Json/TimeSpanJsonConverter.cs @@ -33,7 +33,7 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null to non-nullable type '{typeToConvert.GetTypeId()}'."); } // Handle number tokens (treat as ticks) @@ -51,16 +51,16 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null string to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null string to non-nullable type '{typeToConvert.GetTypeId()}'."); } if (TimeSpan.TryParse(stringValue, CultureInfo.InvariantCulture, out var timeSpanResult)) return timeSpanResult; - throw new JsonException($"Unable to convert '{stringValue}' to {typeof(TimeSpan).GetTypeName(pretty: true)}."); + throw new JsonException($"Unable to convert '{stringValue}' to {typeof(TimeSpan).GetTypeId()}."); } - throw new JsonException($"Expected string or number token but got {reader.TokenType} for type {typeToConvert.GetTypeName(pretty: true)}"); + throw new JsonException($"Expected string or number token but got {reader.TokenType} for type '{typeToConvert.GetTypeId()}'"); } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) diff --git a/ReflectorNet/src/Converter/Json/TypeJsonConverter.cs b/ReflectorNet/src/Converter/Json/TypeJsonConverter.cs index e7302410..572d0b2c 100644 --- a/ReflectorNet/src/Converter/Json/TypeJsonConverter.cs +++ b/ReflectorNet/src/Converter/Json/TypeJsonConverter.cs @@ -60,7 +60,7 @@ public override void Write(Utf8JsonWriter writer, Type value, JsonSerializerOpti return; } - writer.WriteStringValue(value.GetTypeName(pretty: false)); + writer.WriteStringValue(value.GetTypeId()); } } } \ No newline at end of file diff --git a/ReflectorNet/src/Converter/Json/UInt16JsonConverter.cs b/ReflectorNet/src/Converter/Json/UInt16JsonConverter.cs index 47f7cbc2..d2d969ce 100644 --- a/ReflectorNet/src/Converter/Json/UInt16JsonConverter.cs +++ b/ReflectorNet/src/Converter/Json/UInt16JsonConverter.cs @@ -32,7 +32,7 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null to non-nullable type '{typeToConvert.GetTypeId()}'."); } // Handle direct number tokens @@ -51,13 +51,13 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null string to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null string to non-nullable type '{typeToConvert.GetTypeId()}'."); } return ParseUInt16(stringValue); } - throw new JsonException($"Expected string or number token but got {reader.TokenType} for type {typeToConvert.GetTypeName(pretty: true)}"); + throw new JsonException($"Expected string or number token but got {reader.TokenType} for type '{typeToConvert.GetTypeId()}'"); } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) @@ -69,14 +69,14 @@ private static ushort ParseUInt16(string stringValue) { if (ushort.TryParse(stringValue, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) return result; - throw new JsonException($"Unable to convert '{stringValue}' to {typeof(ushort).GetTypeName(pretty: true)}."); + throw new JsonException($"Unable to convert '{stringValue}' to {typeof(ushort).GetTypeId()}."); } private static ushort ConvertToUInt16(double value) { if (value >= ushort.MinValue && value <= ushort.MaxValue && value == Math.Floor(value)) return (ushort)value; - throw new JsonException($"Value {value} is out of range for {typeof(ushort).GetTypeName(pretty: true)}."); + throw new JsonException($"Value {value} is out of range for {typeof(ushort).GetTypeId()}."); } } } \ No newline at end of file diff --git a/ReflectorNet/src/Converter/Json/UInt32JsonConverter.cs b/ReflectorNet/src/Converter/Json/UInt32JsonConverter.cs index 0036a804..ff8d3ef1 100644 --- a/ReflectorNet/src/Converter/Json/UInt32JsonConverter.cs +++ b/ReflectorNet/src/Converter/Json/UInt32JsonConverter.cs @@ -32,7 +32,7 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null to non-nullable type '{typeToConvert.GetTypeId()}'."); } // Handle direct number tokens @@ -51,13 +51,13 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null string to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null string to non-nullable type '{typeToConvert.GetTypeId()}'."); } return ParseUInt32(stringValue); } - throw new JsonException($"Expected string or number token but got {reader.TokenType} for type {typeToConvert.GetTypeName(pretty: true)}"); + throw new JsonException($"Expected string or number token but got {reader.TokenType} for type '{typeToConvert.GetTypeId()}'"); } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) @@ -69,14 +69,14 @@ private static uint ParseUInt32(string stringValue) { if (uint.TryParse(stringValue, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) return result; - throw new JsonException($"Unable to convert '{stringValue}' to {typeof(uint).GetTypeName(pretty: true)}."); + throw new JsonException($"Unable to convert '{stringValue}' to {typeof(uint).GetTypeId()}."); } private static uint ConvertToUInt32(double value) { if (value >= uint.MinValue && value <= uint.MaxValue && value == Math.Floor(value)) return (uint)value; - throw new JsonException($"Value {value} is out of range for {typeof(uint).GetTypeName(pretty: true)}."); + throw new JsonException($"Value {value} is out of range for {typeof(uint).GetTypeId()}."); } } } \ No newline at end of file diff --git a/ReflectorNet/src/Converter/Json/UInt64JsonConverter.cs b/ReflectorNet/src/Converter/Json/UInt64JsonConverter.cs index 2a5415ee..9fdc0dec 100644 --- a/ReflectorNet/src/Converter/Json/UInt64JsonConverter.cs +++ b/ReflectorNet/src/Converter/Json/UInt64JsonConverter.cs @@ -32,7 +32,7 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null to non-nullable type '{typeToConvert.GetTypeId()}'."); } // Handle direct number tokens @@ -51,13 +51,13 @@ public override bool CanConvert(Type typeToConvert) if (Nullable.GetUnderlyingType(typeToConvert) != null) return null; - throw new JsonException($"Cannot convert null string to non-nullable type {typeToConvert.GetTypeName(pretty: true)}."); + throw new JsonException($"Cannot convert null string to non-nullable type '{typeToConvert.GetTypeId()}'."); } return ParseUInt64(stringValue); } - throw new JsonException($"Expected string or number token but got {reader.TokenType} for type {typeToConvert.GetTypeName(pretty: true)}"); + throw new JsonException($"Expected string or number token but got {reader.TokenType} for type '{typeToConvert.GetTypeId()}'"); } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) @@ -69,14 +69,14 @@ private static ulong ParseUInt64(string stringValue) { if (ulong.TryParse(stringValue, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) return result; - throw new JsonException($"Unable to convert '{stringValue}' to {typeof(ulong).GetTypeName(pretty: true)}."); + throw new JsonException($"Unable to convert '{stringValue}' to {typeof(ulong).GetTypeId()}."); } private static ulong ConvertToUInt64(double value) { if (value >= ulong.MinValue && value <= ulong.MaxValue && value == Math.Floor(value)) return (ulong)value; - throw new JsonException($"Value {value} is out of range for {typeof(ulong).GetTypeName(pretty: true)}."); + throw new JsonException($"Value {value} is out of range for {typeof(ulong).GetTypeId()}."); } } } \ No newline at end of file diff --git a/ReflectorNet/src/Converter/Reflection/ArrayReflectionConverter.Deserialize.cs b/ReflectorNet/src/Converter/Reflection/ArrayReflectionConverter.Deserialize.cs index 1b3ec660..4e3c96dc 100644 --- a/ReflectorNet/src/Converter/Reflection/ArrayReflectionConverter.Deserialize.cs +++ b/ReflectorNet/src/Converter/Reflection/ArrayReflectionConverter.Deserialize.cs @@ -81,9 +81,9 @@ public partial class ArrayReflectionConverter : BaseReflectionConverter logger.LogWarning("{padding}{icon} Failed to get element type for array type '{typeName}'", padding, Consts.Emoji.Warn, - type.GetTypeName(pretty: true)); + type.GetTypeId()); } - logs?.Warning($"Failed to get element type for array type '{type.GetTypeName(pretty: true)}'.", depth); + logs?.Warning($"Failed to get element type for array type '{type.GetTypeId()}'.", depth); return null; } @@ -95,9 +95,9 @@ public partial class ArrayReflectionConverter : BaseReflectionConverter logger.LogWarning("{padding}{icon} Failed to create array instance for type '{typeName}'", padding, Consts.Emoji.Warn, - type.GetTypeName(pretty: true)); + type.GetTypeId()); } - logs?.Warning($"Failed to create array instance for type '{type.GetTypeName(pretty: true)}'.", depth); + logs?.Warning($"Failed to create array instance for type '{type.GetTypeId()}'.", depth); return null; } @@ -138,7 +138,7 @@ public partial class ArrayReflectionConverter : BaseReflectionConverter logger.LogWarning("{padding}{icon} Failed to create list instance for type '{typeName}'", padding, Consts.Emoji.Warn, - type.GetTypeName(pretty: true)); + type.GetTypeId()); } return null; } @@ -151,7 +151,7 @@ public partial class ArrayReflectionConverter : BaseReflectionConverter logger.LogError("{padding}{icon} Failed to find 'Add' method on list type='{typeName}'", padding, Consts.Emoji.Fail, - type.GetTypeName(pretty: true)); + type.GetTypeId()); } return null; } @@ -177,11 +177,11 @@ public partial class ArrayReflectionConverter : BaseReflectionConverter i++; } - logger?.LogInformation("{padding}Successfully created list of type='{typeName}'", padding, list.GetType().GetTypeName(pretty: true)); + logger?.LogInformation("{padding}Successfully created list of type='{typeName}'", padding, list.GetType().GetTypeId()); return list; } - logger?.LogWarning("{padding}Type '{typeName}' is neither array nor generic list", padding, type.GetTypeName(pretty: true)); + logger?.LogWarning("{padding}Type '{typeName}' is neither array nor generic list", padding, type.GetTypeId()); return null; } @@ -200,7 +200,7 @@ protected override bool TryDeserializeValueInternal( { logger.LogTrace("{padding}TryDeserializeValueInternal type='{typeName}', name='{name}', AllowCascadeSerialize={AllowCascadeSerialize}, Converter='{ConverterName}'", padding, - type.GetTypeName(pretty: true), + type.GetTypeId(), serializedMember.name.ValueOrNull(), AllowCascadeSerialization, GetType().Name); @@ -217,7 +217,7 @@ protected override bool TryDeserializeValueInternal( logger.LogWarning("{padding}{icon} 'value' is null for type='{typeName}', name='{name}'. Converter='{ConverterName}'", padding, Consts.Emoji.Warn, - type.GetTypeName(pretty: false), + type.GetTypeId(), serializedMember.name.ValueOrNull(), GetType().Name); } diff --git a/ReflectorNet/src/Converter/Reflection/ArrayReflectionConverter.cs b/ReflectorNet/src/Converter/Reflection/ArrayReflectionConverter.cs index ee8f8ba2..2aeca824 100644 --- a/ReflectorNet/src/Converter/Reflection/ArrayReflectionConverter.cs +++ b/ReflectorNet/src/Converter/Reflection/ArrayReflectionConverter.cs @@ -164,7 +164,7 @@ public override bool SetField( // Check if field type matches parsed value type if (!TypeUtils.IsCastable(type, fieldInfo.FieldType)) { - logs?.Error($"Parsed value type '{type.GetTypeName(pretty: false)}' is not assignable to field type '{fieldInfo.FieldType.GetTypeName(pretty: false)}' for field '{fieldInfo.Name}'.", depth); + logs?.Error($"Parsed value type '{type?.GetTypeId().ValueOrNull()}' is not assignable to field type '{fieldInfo.FieldType.GetTypeId()}' for field '{fieldInfo.Name}'.", depth); return false; } @@ -211,7 +211,7 @@ public override bool SetProperty( // Check if property type matches parsed value type if (!TypeUtils.IsCastable(type, propertyInfo.PropertyType)) { - logs?.Error($"Parsed value type '{type.GetTypeName(pretty: false)}' is not assignable to property type '{propertyInfo.PropertyType.GetTypeName(pretty: false)}' for property '{propertyInfo.Name}'.", depth); + logs?.Error($"Parsed value type '{type?.GetTypeId().ValueOrNull()}' is not assignable to property type '{propertyInfo.PropertyType.GetTypeId()}' for property '{propertyInfo.Name}'.", depth); return false; } diff --git a/ReflectorNet/src/Converter/Reflection/Base/BaseReflectionConverter.DefaultValue.cs b/ReflectorNet/src/Converter/Reflection/Base/BaseReflectionConverter.DefaultValue.cs index 1e346914..ffa5f411 100644 --- a/ReflectorNet/src/Converter/Reflection/Base/BaseReflectionConverter.DefaultValue.cs +++ b/ReflectorNet/src/Converter/Reflection/Base/BaseReflectionConverter.DefaultValue.cs @@ -87,7 +87,7 @@ public abstract partial class BaseReflectionConverter : IReflectionConverter { var elementType = type.GetElementType(); if (elementType == null) - throw new ArgumentException($"Array type '{type.FullName}' has no element type."); + throw new ArgumentException($"Array type '{type.GetTypeId()}' has no element type."); return Array.CreateInstance(elementType, 0); // Create empty array } @@ -96,7 +96,7 @@ public abstract partial class BaseReflectionConverter : IReflectionConverter if (type.IsInterface || type.IsAbstract) { // Cannot create instance of interface or abstract class - throw new InvalidOperationException($"Cannot create instance of type '{type.GetTypeName(pretty: false)}' because it is an interface or abstract class."); + throw new InvalidOperationException($"Cannot create instance of type '{type.GetTypeId()}' because it is an interface or abstract class."); } // Handle classes with parameterless constructors @@ -128,7 +128,7 @@ public abstract partial class BaseReflectionConverter : IReflectionConverter } catch { - throw new ArgumentException($"Type '{type.GetTypeName(pretty: false)}' does not have a constructor or is not a value type or primitive type."); + throw new ArgumentException($"Type '{type.GetTypeId()}' does not have a constructor or is not a value type or primitive type."); } } diff --git a/ReflectorNet/src/Converter/Reflection/Base/BaseReflectionConverter.Deserialize.cs b/ReflectorNet/src/Converter/Reflection/Base/BaseReflectionConverter.Deserialize.cs index cca3d708..ef29b665 100644 --- a/ReflectorNet/src/Converter/Reflection/Base/BaseReflectionConverter.Deserialize.cs +++ b/ReflectorNet/src/Converter/Reflection/Base/BaseReflectionConverter.Deserialize.cs @@ -84,7 +84,7 @@ public abstract partial class BaseReflectionConverter : IReflectionConverter result ??= CreateInstance(reflector, type!); if (logger?.IsEnabled(LogLevel.Trace) == true) - logger.LogTrace($"{padding}{Consts.Emoji.Field} Deserialize '{nameof(SerializedMember.fields)}' type='{type.GetTypeName(pretty: true)}' name='{(StringUtils.IsNullOrEmpty(data.name) ? fallbackName : data.name).ValueOrNull()}'."); + logger.LogTrace($"{padding}{Consts.Emoji.Field} Deserialize '{nameof(SerializedMember.fields)}' type='{type?.GetTypeId().ValueOrNull()}' name='{(StringUtils.IsNullOrEmpty(data.name) ? fallbackName : data.name).ValueOrNull()}'."); foreach (var field in data.fields) { @@ -109,9 +109,9 @@ public abstract partial class BaseReflectionConverter : IReflectionConverter if (fieldInfo == null) { if (logger?.IsEnabled(LogLevel.Warning) == true) - logger.LogWarning($"{padding}{Consts.Emoji.Warn} Field '{field.name}' not found on type '{type.GetTypeName(pretty: false)}'."); + logger.LogWarning($"{padding}{Consts.Emoji.Warn} Field '{field.name}' not found on type '{type.GetTypeId()}'."); - logs?.Warning($"Field '{field.name}' not found on type '{type.GetTypeName(pretty: false)}'.", depth); + logs?.Warning($"Field '{field.name}' not found on type '{type.GetTypeId()}'.", depth); continue; } @@ -124,7 +124,7 @@ public abstract partial class BaseReflectionConverter : IReflectionConverter result ??= CreateInstance(reflector, type!); if (logger?.IsEnabled(LogLevel.Trace) == true) - logger.LogTrace($"{padding}{Consts.Emoji.Property} Deserialize '{nameof(SerializedMember.props)}' type='{type.GetTypeName(pretty: true)}' name='{(StringUtils.IsNullOrEmpty(data.name) ? fallbackName : data.name).ValueOrNull()}'."); + logger.LogTrace($"{padding}{Consts.Emoji.Property} Deserialize '{nameof(SerializedMember.props)}' type='{type?.GetTypeId().ValueOrNull()}' name='{(StringUtils.IsNullOrEmpty(data.name) ? fallbackName : data.name).ValueOrNull()}'."); foreach (var property in data.props) { @@ -149,18 +149,18 @@ public abstract partial class BaseReflectionConverter : IReflectionConverter if (propertyInfo == null) { if (logger?.IsEnabled(LogLevel.Warning) == true) - logger.LogWarning($"{padding}{Consts.Emoji.Warn} Property '{property.name}' not found on type '{type.GetTypeName(pretty: false)}'."); + logger.LogWarning($"{padding}{Consts.Emoji.Warn} Property '{property.name}' not found on type '{type.GetTypeId()}'."); - logs?.Warning($"Property '{property.name}' not found on type '{type.GetTypeName(pretty: false)}'.", depth); + logs?.Warning($"Property '{property.name}' not found on type '{type.GetTypeId()}'.", depth); continue; } if (!propertyInfo.CanWrite) { if (logger?.IsEnabled(LogLevel.Warning) == true) - logger.LogWarning($"{padding}{Consts.Emoji.Warn} Property '{property.name}' on type '{type.GetTypeName(pretty: false)}' is read-only and cannot be set."); + logger.LogWarning($"{padding}{Consts.Emoji.Warn} Property '{property.name}' on type '{type.GetTypeId()}' is read-only and cannot be set."); - logs?.Warning($"Property '{property.name}' on type '{type.GetTypeName(pretty: false)}' is read-only and cannot be set.", depth); + logs?.Warning($"Property '{property.name}' on type '{type.GetTypeId()}' is read-only and cannot be set.", depth); continue; } @@ -233,7 +233,7 @@ protected virtual bool TryDeserializeValue( } if (logger?.IsEnabled(LogLevel.Trace) == true) - logger.LogTrace($"{padding}{Consts.Emoji.Start} Deserialize 'value', type='{type.GetTypeName(pretty: true)}' name='{data.name.ValueOrNull()}'."); + logger.LogTrace($"{padding}{Consts.Emoji.Start} Deserialize 'value', type='{type.GetTypeId()}' name='{data.name.ValueOrNull()}'."); var success = TryDeserializeValueInternal( reflector, @@ -247,12 +247,12 @@ protected virtual bool TryDeserializeValue( if (success) { if (logger?.IsEnabled(LogLevel.Trace) == true) - logger.LogTrace($"{padding}{Consts.Emoji.Done} Deserialized '{type.GetTypeName(pretty: true)}'."); + logger.LogTrace($"{padding}{Consts.Emoji.Done} Deserialized '{type.GetTypeId()}'."); } else { if (logger?.IsEnabled(LogLevel.Error) == true) - logger.LogError($"{padding}{Consts.Emoji.Fail} Deserialization '{type.GetTypeName(pretty: false)}' failed. Converter: {GetType().GetTypeShortName()}"); + logger.LogError($"{padding}{Consts.Emoji.Fail} Deserialization '{type.GetTypeId()}' failed. Converter: {GetType().GetTypeShortName()}"); } return success; @@ -303,16 +303,16 @@ protected virtual bool TryDeserializeValueInternal( catch (JsonException ex) { if (logger?.IsEnabled(LogLevel.Warning) == true) - logger.LogWarning($"{padding}{Consts.Emoji.Warn} Deserialize 'value', type='{type.GetTypeName(pretty: false)}' name='{data.name.ValueOrNull()}':\n{padding}{ex.Message}\n{ex.StackTrace}"); + logger.LogWarning($"{padding}{Consts.Emoji.Warn} Deserialize 'value', type='{type.GetTypeId()}' name='{data.name.ValueOrNull()}':\n{padding}{ex.Message}\n{ex.StackTrace}"); - logs?.Warning($"Failed to deserialize member '{data.name.ValueOrNull()}' of type '{type.GetTypeName(pretty: true)}':\n{ex.Message}", depth); + logs?.Warning($"Failed to deserialize member '{data.name.ValueOrNull()}' of type '{type.GetTypeId()}':\n{ex.Message}", depth); } catch (NotSupportedException ex) { if (logger?.IsEnabled(LogLevel.Warning) == true) - logger.LogWarning($"{padding}{Consts.Emoji.Warn} Deserialize 'value', type='{type.GetTypeName(pretty: false)}' name='{data.name.ValueOrNull()}':\n{padding}{ex.Message}\n{ex.StackTrace}"); + logger.LogWarning($"{padding}{Consts.Emoji.Warn} Deserialize 'value', type='{type.GetTypeId()}' name='{data.name.ValueOrNull()}':\n{padding}{ex.Message}\n{ex.StackTrace}"); - logs?.Warning($"Unsupported type '{type.GetTypeName(pretty: false)}' for member '{data.name.ValueOrNull()}':\n{ex.Message}", depth); + logs?.Warning($"Unsupported type '{type.GetTypeId()}' for member '{data.name.ValueOrNull()}':\n{ex.Message}", depth); } result = reflector.GetDefaultValue(type); @@ -340,8 +340,8 @@ protected virtual bool TryDeserializeValueInternal( } catch (Exception ex) { - logs?.Error($"Failed to deserialize value'{data.name.ValueOrNull()}' of type '{type.GetTypeName(pretty: false)}':\n{ex.Message}", depth); - logger?.LogCritical($"{padding}{Consts.Emoji.Fail} Deserialize 'value', type='{type.GetTypeName(pretty: false)}' name='{data.name.ValueOrNull()}':\n{padding}{ex.Message}\n{ex.StackTrace}"); + logs?.Error($"Failed to deserialize value'{data.name.ValueOrNull()}' of type '{type.GetTypeId()}':\n{ex.Message}", depth); + logger?.LogCritical($"{padding}{Consts.Emoji.Fail} Deserialize 'value', type='{type.GetTypeId()}' name='{data.name.ValueOrNull()}':\n{padding}{ex.Message}\n{ex.StackTrace}"); result = reflector.GetDefaultValue(type); return false; } diff --git a/ReflectorNet/src/Converter/Reflection/Base/BaseReflectionConverter.Populate.cs b/ReflectorNet/src/Converter/Reflection/Base/BaseReflectionConverter.Populate.cs index e5961f0a..ab4958c7 100644 --- a/ReflectorNet/src/Converter/Reflection/Base/BaseReflectionConverter.Populate.cs +++ b/ReflectorNet/src/Converter/Reflection/Base/BaseReflectionConverter.Populate.cs @@ -55,19 +55,19 @@ public virtual bool TryPopulate( if (obj == null) { if (logger?.IsEnabled(LogLevel.Error) == true) - logger.LogError($"{padding}Object '{data.name.ValueOrNull()}' population failed: Object is null. Instance creation failed for type '{objType.GetTypeName(pretty: false)}'."); + logger.LogError($"{padding}Object '{data.name.ValueOrNull()}' population failed: Object is null. Instance creation failed for type '{objType.GetTypeId()}'."); if (logs != null) - logs.Error($"Object '{data.name.ValueOrNull()}' population failed: Object is null. Instance creation failed for type '{objType.GetTypeName(pretty: false)}'.", depth); + logs.Error($"Object '{data.name.ValueOrNull()}' population failed: Object is null. Instance creation failed for type '{objType.GetTypeId()}'.", depth); return false; } if (logger?.IsEnabled(LogLevel.Trace) == true) - logger.LogTrace($"{padding}Object '{data.name.ValueOrNull()}' populated with type '{objType.GetTypeName(pretty: true)}'."); + logger.LogTrace($"{padding}Object '{data.name.ValueOrNull()}' populated with type '{objType.GetTypeId()}'."); if (logs != null) - logs.Success($"Object '{data.name.ValueOrNull()}' populated with type '{objType.GetTypeName(pretty: true)}'.", depth); + logs.Success($"Object '{data.name.ValueOrNull()}' populated with type '{objType.GetTypeId()}'.", depth); return true; } @@ -75,10 +75,10 @@ public virtual bool TryPopulate( if (!TypeUtils.IsCastable(obj.GetType(), objType)) { if (logger?.IsEnabled(LogLevel.Error) == true) - logger.LogError($"{padding}Type mismatch: '{data.typeName}' vs '{obj.GetType().GetTypeName(pretty: false).ValueOrNull()}'."); + logger.LogError($"{padding}Type mismatch: '{data.typeName}' vs '{obj.GetType().GetTypeId().ValueOrNull()}'."); if (logs != null) - logs.Error($"Type mismatch: '{data.typeName}' vs '{obj.GetType().GetTypeName(pretty: false).ValueOrNull()}'.", depth); + logs.Error($"Type mismatch: '{data.typeName}' vs '{obj.GetType().GetTypeId().ValueOrNull()}'.", depth); return false; } @@ -342,7 +342,7 @@ protected virtual bool TryPopulateField( logger.LogTrace($"{padding}Populate field type='{fieldInfo.FieldType.GetTypeShortName()}', name='{fieldInfo.Name.ValueOrNull()}'. Converter='{GetType().GetTypeShortName()}'."); if (logs != null) - logs.Info($"Populate field type='{fieldInfo.FieldType.GetTypeName(pretty: false).ValueOrNull()}', name='{fieldInfo.Name.ValueOrNull()}'. Converter='{GetType().GetTypeShortName()}'.", depth); + logs.Info($"Populate field type='{fieldInfo.FieldType.GetTypeId().ValueOrNull()}', name='{fieldInfo.Name.ValueOrNull()}'. Converter='{GetType().GetTypeShortName()}'.", depth); var currentValue = fieldInfo.GetValue(obj); @@ -497,10 +497,10 @@ protected virtual bool TryPopulateProperty( try { if (logger?.IsEnabled(LogLevel.Trace) == true) - logger.LogTrace($"{padding}Populate property type='{propInfo.PropertyType.GetTypeName(pretty: false).ValueOrNull()}', name='{propInfo.Name.ValueOrNull()}'. Converter='{GetType().GetTypeShortName()}'."); + logger.LogTrace($"{padding}Populate property type='{propInfo.PropertyType.GetTypeId().ValueOrNull()}', name='{propInfo.Name.ValueOrNull()}'. Converter='{GetType().GetTypeShortName()}'."); if (logs != null) - logs.Info($"Populate property type='{propInfo.PropertyType.GetTypeName(pretty: false).ValueOrNull()}', name='{propInfo.Name.ValueOrNull()}'. Converter='{GetType().GetTypeShortName()}'.", depth); + logs.Info($"Populate property type='{propInfo.PropertyType.GetTypeId().ValueOrNull()}', name='{propInfo.Name.ValueOrNull()}'. Converter='{GetType().GetTypeShortName()}'.", depth); var currentValue = propInfo.GetValue(obj); diff --git a/ReflectorNet/src/Converter/Reflection/Base/BaseReflectionConverter.Serialize.cs b/ReflectorNet/src/Converter/Reflection/Base/BaseReflectionConverter.Serialize.cs index 31d127e1..1682ca5d 100644 --- a/ReflectorNet/src/Converter/Reflection/Base/BaseReflectionConverter.Serialize.cs +++ b/ReflectorNet/src/Converter/Reflection/Base/BaseReflectionConverter.Serialize.cs @@ -19,10 +19,17 @@ public abstract partial class BaseReflectionConverter : IReflectionConverter protected virtual IEnumerable GetIgnoredFields() => Enumerable.Empty(); protected virtual IEnumerable GetIgnoredProperties() => Enumerable.Empty(); - public virtual SerializedMember Serialize(Reflector reflector, object? obj, Type? type = null, string? name = null, bool recursive = true, + public virtual SerializedMember Serialize( + Reflector reflector, + object? obj, + Type? type = null, + string? name = null, + bool recursive = true, BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, - int depth = 0, Logs? logs = null, - ILogger? logger = null, SerializationContext? context = null) + int depth = 0, + Logs? logs = null, + ILogger? logger = null, + SerializationContext? context = null) { return InternalSerialize(reflector, obj, type: type ?? obj?.GetType() ?? typeof(T), @@ -35,8 +42,14 @@ public virtual SerializedMember Serialize(Reflector reflector, object? obj, Type context: context); } - protected virtual SerializedMemberList? SerializeFields(Reflector reflector, object obj, BindingFlags flags, - int depth = 0, Logs? logs = null, ILogger? logger = null, SerializationContext? context = null) + protected virtual SerializedMemberList? SerializeFields( + Reflector reflector, + object obj, + BindingFlags flags, + int depth = 0, + Logs? logs = null, + ILogger? logger = null, + SerializationContext? context = null) { var serializedFields = default(SerializedMemberList); var objType = obj.GetType(); @@ -67,8 +80,14 @@ public virtual SerializedMember Serialize(Reflector reflector, object? obj, Type return serializedFields; } - protected virtual SerializedMemberList? SerializeProperties(Reflector reflector, object obj, BindingFlags flags, - int depth = 0, Logs? logs = null, ILogger? logger = null, SerializationContext? context = null) + protected virtual SerializedMemberList? SerializeProperties( + Reflector reflector, + object obj, + BindingFlags flags, + int depth = 0, + Logs? logs = null, + ILogger? logger = null, + SerializationContext? context = null) { var serializedProperties = default(SerializedMemberList); var objType = obj.GetType(); @@ -102,9 +121,16 @@ public virtual SerializedMember Serialize(Reflector reflector, object? obj, Type return serializedProperties; } - protected abstract SerializedMember InternalSerialize(Reflector reflector, object? obj, Type type, string? name = null, bool recursive = true, + protected abstract SerializedMember InternalSerialize( + Reflector reflector, + object? obj, + Type type, + string? name = null, + bool recursive = true, BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, - int depth = 0, Logs? logs = null, - ILogger? logger = null, SerializationContext? context = null); + int depth = 0, + Logs? logs = null, + ILogger? logger = null, + SerializationContext? context = null); } } \ No newline at end of file diff --git a/ReflectorNet/src/Converter/Reflection/GenericReflectionConverter.cs b/ReflectorNet/src/Converter/Reflection/GenericReflectionConverter.cs index af647f95..785d7a13 100644 --- a/ReflectorNet/src/Converter/Reflection/GenericReflectionConverter.cs +++ b/ReflectorNet/src/Converter/Reflection/GenericReflectionConverter.cs @@ -39,7 +39,7 @@ protected override SerializedMember InternalSerialize( ? new SerializedMember() { name = name, - typeName = type.GetTypeName(pretty: false) ?? string.Empty, + typeName = type.GetTypeId() ?? string.Empty, fields = base.SerializeFields( reflector: reflector, obj: obj, @@ -60,7 +60,7 @@ protected override SerializedMember InternalSerialize( } : SerializedMember.FromJson(type, obj.ToJson(reflector), name: name); } - throw new ArgumentException($"Unsupported type: '{type.GetTypeName(pretty: false)}' for converter '{GetType().GetTypeShortName()}'."); + throw new ArgumentException($"Unsupported type: '{type.GetTypeId()}' for converter '{GetType().GetTypeShortName()}'."); } // GetSerializableFields and GetSerializableProperties inherited from BaseReflectionConverter @@ -110,7 +110,7 @@ public override bool SetField( // Check if field type matches parsed value type if (!TypeUtils.IsCastable(type, fieldInfo.FieldType)) { - logs?.Error($"Parsed value type '{type.GetTypeName(pretty: false)}' is not assignable to field type '{fieldInfo.FieldType.GetTypeName(pretty: false)}' for field '{fieldInfo.Name}'.", depth); + logs?.Error($"Parsed value type '{type?.GetTypeId().ValueOrNull()}' is not assignable to field type '{fieldInfo.FieldType.GetTypeId()}' for field '{fieldInfo.Name}'.", depth); return false; } @@ -158,7 +158,7 @@ public override bool SetProperty( // Check if property type matches parsed value type if (!TypeUtils.IsCastable(type, propertyInfo.PropertyType)) { - logs?.Error($"Parsed value type '{type.GetTypeName(pretty: false)}' is not assignable to property type '{propertyInfo.PropertyType.GetTypeName(pretty: false)}' for property '{propertyInfo.Name}'.", depth); + logs?.Error($"Parsed value type '{type?.GetTypeId().ValueOrNull()}' is not assignable to property type '{propertyInfo.PropertyType.GetTypeId()}' for property '{propertyInfo.Name}'.", depth); return false; } diff --git a/ReflectorNet/src/Converter/Reflection/PrimitiveReflectionConverter.cs b/ReflectorNet/src/Converter/Reflection/PrimitiveReflectionConverter.cs index 88f50e3c..a0326e97 100644 --- a/ReflectorNet/src/Converter/Reflection/PrimitiveReflectionConverter.cs +++ b/ReflectorNet/src/Converter/Reflection/PrimitiveReflectionConverter.cs @@ -27,10 +27,16 @@ public override int SerializationPriority(Type type, ILogger? logger = null) ? MAX_DEPTH + 1 : 0; } - protected override SerializedMember InternalSerialize(Reflector reflector, object? obj, Type type, string? name = null, bool recursive = true, + protected override SerializedMember InternalSerialize( + Reflector reflector, + object? obj, + Type type, + string? name = null, + bool recursive = true, BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, int depth = 0, Logs? logs = null, - ILogger? logger = null, SerializationContext? context = null) + ILogger? logger = null, + SerializationContext? context = null) { if (obj == null) return SerializedMember.FromJson(type, json: null, name: name); @@ -56,7 +62,14 @@ protected override SerializedMember InternalSerialize(Reflector reflector, objec return null; } - protected override bool SetValue(Reflector reflector, ref object? obj, Type type, JsonElement? value, int depth = 0, Logs? logs = null, ILogger? logger = null) + protected override bool SetValue( + Reflector reflector, + ref object? obj, + Type type, + JsonElement? value, + int depth = 0, + Logs? logs = null, + ILogger? logger = null) { var parsedValue = value.Deserialize(type, reflector); Print.SetNewValue(ref obj, ref parsedValue, type, depth, logs, logger); @@ -84,7 +97,7 @@ public override bool SetField( // Check if field type matches parsed value type if (!TypeUtils.IsCastable(type, fieldInfo.FieldType)) { - logs?.Error($"Parsed value type '{type.GetTypeName(pretty: false)}' is not assignable to field type '{fieldInfo.FieldType.GetTypeName(pretty: false)}' for field '{fieldInfo.Name}'.", depth); + logs?.Error($"Parsed value type '{type?.GetTypeId().ValueOrNull()}' is not assignable to field type '{fieldInfo.FieldType.GetTypeId()}' for field '{fieldInfo.Name}'.", depth); return false; } @@ -120,7 +133,7 @@ public override bool SetProperty( // Check if property type matches parsed value type if (!TypeUtils.IsCastable(type, propertyInfo.PropertyType)) { - logs?.Error($"Parsed value type '{type.GetTypeName(pretty: false)}' is not assignable to property type '{propertyInfo.PropertyType.GetTypeName(pretty: false)}' for property '{propertyInfo.Name}'.", depth); + logs?.Error($"Parsed value type '{type?.GetTypeId().ValueOrNull()}' is not assignable to property type '{propertyInfo.PropertyType.GetTypeId()}' for property '{propertyInfo.Name}'.", depth); return false; } diff --git a/ReflectorNet/src/Converter/Reflection/Specialized/TypeReflectionConverter.cs b/ReflectorNet/src/Converter/Reflection/Specialized/TypeReflectionConverter.cs index 6999dbf5..2be5a777 100644 --- a/ReflectorNet/src/Converter/Reflection/Specialized/TypeReflectionConverter.cs +++ b/ReflectorNet/src/Converter/Reflection/Specialized/TypeReflectionConverter.cs @@ -38,7 +38,8 @@ protected override SerializedMember InternalSerialize( { if (obj is Type typeObj) { - var typeName = typeObj.GetTypeName(pretty: false); + // Use typeObj (the actual Type being serialized) not type (which is RuntimeType) + var typeName = typeObj.GetTypeId(); return SerializedMember.FromValue(reflector, type, typeName, name: name); } diff --git a/ReflectorNet/src/Extension/ExtensionsSerializedMemberList.cs b/ReflectorNet/src/Extension/ExtensionsSerializedMemberList.cs index 2ad6e5fe..e736151c 100644 --- a/ReflectorNet/src/Extension/ExtensionsSerializedMemberList.cs +++ b/ReflectorNet/src/Extension/ExtensionsSerializedMemberList.cs @@ -84,7 +84,7 @@ public static void EnhanceTypes(this SerializedMemberList? parameters, MethodInf if (string.IsNullOrEmpty(parameter.typeName)) { var methodParameter = methodParameters[i]; - var typeName = methodParameter?.ParameterType?.GetTypeName(pretty: false); + var typeName = methodParameter?.ParameterType?.GetTypeId(); if (typeName == null) continue; parameter.typeName = typeName; diff --git a/ReflectorNet/src/Extension/ExtensionsType.cs b/ReflectorNet/src/Extension/ExtensionsType.cs index 25b73db8..aefb3638 100644 --- a/ReflectorNet/src/Extension/ExtensionsType.cs +++ b/ReflectorNet/src/Extension/ExtensionsType.cs @@ -16,7 +16,13 @@ public static class ExtensionsType public static JsonNode? GetSchema(this Type type, Reflector reflector) => reflector.GetSchema(type); public static JsonNode? GetSchemaRef(this Type type, Reflector reflector) => reflector.GetSchemaRef(type); public static string GetTypeShortName(this Type? type) => TypeUtils.GetTypeShortName(type); - public static string GetTypeName(this Type? type, bool pretty = false) => TypeUtils.GetTypeName(type, pretty); + + /// + /// Returns the sanitized type name. + /// 1. Unwraps nullable types. + /// 2. Returns FullName. + /// + public static string Sanitize(this Type? type) => TypeUtils.Sanitize(type); public static string GetTypeId(this Type type) => TypeUtils.GetTypeId(type); public static string GetSchemaTypeId(this Type type) => TypeUtils.GetSchemaTypeId(type); public static bool IsMatch(this Type? type, string? typeName) => TypeUtils.IsNameMatch(type, typeName); diff --git a/ReflectorNet/src/Model/MethodData.cs b/ReflectorNet/src/Model/MethodData.cs index d50b5e36..6fb5b6a8 100644 --- a/ReflectorNet/src/Model/MethodData.cs +++ b/ReflectorNet/src/Model/MethodData.cs @@ -42,12 +42,12 @@ public MethodData(Reflector reflector, MethodInfo methodInfo, bool justRef = fal { IsStatic = methodInfo.IsStatic; IsPublic = methodInfo.IsPublic; - ReturnType = methodInfo.ReturnType.GetTypeName(pretty: false); + ReturnType = methodInfo.ReturnType.GetTypeId(); ReturnSchema = methodInfo.ReturnType == typeof(void) ? null : justRef - ? reflector.GetSchemaRef(methodInfo.ReturnType) - : reflector.GetSchema(methodInfo.ReturnType); + ? reflector.GetSchemaRef(methodInfo.ReturnType) + : reflector.GetSchema(methodInfo.ReturnType); InputParametersSchema = methodInfo.GetParameters() ?.Select(parameter => justRef ? reflector.GetSchemaRef(parameter.ParameterType) diff --git a/ReflectorNet/src/Model/MethodRef.cs b/ReflectorNet/src/Model/MethodRef.cs index 08202a61..c6f39d04 100644 --- a/ReflectorNet/src/Model/MethodRef.cs +++ b/ReflectorNet/src/Model/MethodRef.cs @@ -62,7 +62,7 @@ public MethodRef() { } public MethodRef(MethodInfo methodInfo) { Namespace = methodInfo.DeclaringType?.Namespace; - TypeName = methodInfo.DeclaringType?.Name ?? string.Empty; + TypeName = methodInfo.DeclaringType?.GetTypeShortName() ?? string.Empty; MethodName = methodInfo.Name; InputParameters = methodInfo.GetParameters() ?.Select(parameter => new Parameter(parameter)) @@ -71,7 +71,7 @@ public MethodRef(MethodInfo methodInfo) public MethodRef(PropertyInfo methodInfo) { Namespace = methodInfo.DeclaringType?.Namespace; - TypeName = methodInfo.DeclaringType?.Name ?? string.Empty; + TypeName = methodInfo.DeclaringType?.GetTypeShortName() ?? string.Empty; MethodName = methodInfo.Name; InputParameters = null; } @@ -103,7 +103,7 @@ public Parameter(string typeName, string? name) } public Parameter(ParameterInfo parameter) { - TypeName = parameter.ParameterType.GetTypeName(pretty: false); + TypeName = parameter.ParameterType.GetTypeId(); Name = parameter.Name; } public override string ToString() diff --git a/ReflectorNet/src/Model/SerializedMember.cs b/ReflectorNet/src/Model/SerializedMember.cs index 142d4981..af5e5949 100644 --- a/ReflectorNet/src/Model/SerializedMember.cs +++ b/ReflectorNet/src/Model/SerializedMember.cs @@ -45,7 +45,7 @@ public SerializedMember() { } protected SerializedMember(Type type, string? name = null) { this.name = name; - this.typeName = type.GetTypeName(pretty: false) ?? throw new ArgumentNullException(nameof(type)); + this.typeName = type.GetTypeId() ?? throw new ArgumentNullException(nameof(type)); } public SerializedMember SetName(string? name) diff --git a/ReflectorNet/src/Reflector/MethodWrapper.cs b/ReflectorNet/src/Reflector/MethodWrapper.cs index 03b00ef0..e930ae75 100644 --- a/ReflectorNet/src/Reflector/MethodWrapper.cs +++ b/ReflectorNet/src/Reflector/MethodWrapper.cs @@ -204,7 +204,7 @@ public virtual bool VerifyParameters(IReadOnlyDictionary? named if (!methodParameter.ParameterType.IsInstanceOfType(parameter.Value)) { - error = $"Parameter '{parameter.Key}' type mismatch. Expected '{methodParameter.ParameterType.GetTypeName(pretty: true)}', but got '{parameter.Value.GetType()}'."; + error = $"Parameter '{parameter.Key}' type mismatch. Expected '{methodParameter.ParameterType.GetTypeId()}', but got '{parameter.Value.GetType()}'."; return false; } } @@ -238,7 +238,7 @@ public virtual bool VerifyParameters(IReadOnlyDictionary? named continue; if (!parameter.ParameterType.IsInstanceOfType(finalParameters[i])) - throw new ArgumentException($"Parameter '{parameter.Name}' type mismatch. Expected '{parameter.ParameterType.GetTypeName(pretty: true)}', but got '{finalParameters[i]?.GetType()}'."); + throw new ArgumentException($"Parameter '{parameter.Name}' type mismatch. Expected '{parameter.ParameterType.GetTypeId()}', but got '{finalParameters[i]?.GetType()}'."); } return finalParameters; @@ -295,7 +295,7 @@ public virtual bool VerifyParameters(IReadOnlyDictionary? named catch (Exception ex2) { // If all parsing attempts fail, throw ArgumentException as expected by tests - throw new ArgumentException($"Unable to convert value to parameter '{methodParameter.Name}' of type '{methodParameter.ParameterType.GetTypeName(pretty: true)}'.\nInput value: {jsonElement}\nOriginal exception: {ex.Message}\nSecond exception: {ex2.Message}"); + throw new ArgumentException($"Unable to convert value to parameter '{methodParameter.Name}' of type '{methodParameter.ParameterType.GetTypeId()}'.\nInput value: {jsonElement}\nOriginal exception: {ex.Message}\nSecond exception: {ex2.Message}"); } } } @@ -310,7 +310,7 @@ public virtual bool VerifyParameters(IReadOnlyDictionary? named return StringUtils.ConvertParameterStringToEnum(value, underlyingType, methodParameter.Name!); } - throw new ArgumentException($"Parameter '{methodParameter.Name}' type mismatch. Expected '{methodParameter.ParameterType.GetTypeName(pretty: true)}', but got '{value?.GetType()}'."); + throw new ArgumentException($"Parameter '{methodParameter.Name}' type mismatch. Expected '{methodParameter.ParameterType.GetTypeId()}', but got '{value?.GetType()}'."); } } @@ -334,7 +334,7 @@ public virtual bool VerifyParameters(IReadOnlyDictionary? named continue; if (!parameter.ParameterType.IsInstanceOfType(finalParameters[i])) - throw new ArgumentException($"Parameter '{parameter.Name}' type mismatch. Expected '{parameter.ParameterType.GetTypeName(pretty: true)}', but got '{finalParameters[i]?.GetType()}'."); + throw new ArgumentException($"Parameter '{parameter.Name}' type mismatch. Expected '{parameter.ParameterType.GetTypeId()}', but got '{finalParameters[i]?.GetType()}'."); } return finalParameters; @@ -379,7 +379,7 @@ public virtual bool VerifyParameters(IReadOnlyDictionary? named catch (Exception ex2) { // If all parsing attempts fail, throw ArgumentException as expected by tests - throw new ArgumentException($"Unable to convert value to parameter '{parameter.Name}' of type '{parameter.ParameterType.GetTypeName(pretty: true)}'.\nInput value: {jsonElement}\nOriginal exception: {ex.Message}\nSecond exception: {ex2.Message}"); + throw new ArgumentException($"Unable to convert value to parameter '{parameter.Name}' of type '{parameter.ParameterType.GetTypeId()}'.\nInput value: {jsonElement}\nOriginal exception: {ex.Message}\nSecond exception: {ex2.Message}"); } } } @@ -394,7 +394,7 @@ public virtual bool VerifyParameters(IReadOnlyDictionary? named return StringUtils.ConvertParameterStringToEnum(value, underlyingType, parameter.Name!); } - throw new ArgumentException($"Parameter '{parameter.Name}' type mismatch. Expected '{parameter.ParameterType.GetTypeName(pretty: true)}', but got '{value?.GetType()}'."); + throw new ArgumentException($"Parameter '{parameter.Name}' type mismatch. Expected '{parameter.ParameterType.GetTypeId()}', but got '{value?.GetType()}'."); } } else if (parameter.HasDefaultValue) diff --git a/ReflectorNet/src/Reflector/Reflector.DefaultValue.cs b/ReflectorNet/src/Reflector/Reflector.DefaultValue.cs index 9c499a9e..9f3d2e75 100644 --- a/ReflectorNet/src/Reflector/Reflector.DefaultValue.cs +++ b/ReflectorNet/src/Reflector/Reflector.DefaultValue.cs @@ -54,7 +54,7 @@ public partial class Reflector var converter = Converters.GetConverter(type); if (converter == null) - throw new ArgumentException($"[Error] Type '{type?.GetTypeName(pretty: false).ValueOrNull()}' not supported for creating instance."); + throw new ArgumentException($"[Error] Type '{type?.GetTypeId().ValueOrNull()}' not supported for creating instance."); return converter.CreateInstance(this, type); } @@ -105,7 +105,7 @@ public partial class Reflector var converter = Converters.GetConverter(type); if (converter == null) - throw new ArgumentException($"[Error] Type '{type?.GetTypeName(pretty: false).ValueOrNull()}' not supported for default value."); + throw new ArgumentException($"[Error] Type '{type?.GetTypeId().ValueOrNull()}' not supported for default value."); return converter.GetDefaultValue(this, type); } diff --git a/ReflectorNet/src/Reflector/Reflector.Error.cs b/ReflectorNet/src/Reflector/Reflector.Error.cs index 8113a5aa..dce25e29 100644 --- a/ReflectorNet/src/Reflector/Reflector.Error.cs +++ b/ReflectorNet/src/Reflector/Reflector.Error.cs @@ -33,14 +33,14 @@ public static string PropertyTypeIsEmpty() => "[Error] Property type is empty. It should be a valid property type."; public static string InvalidInstanceID(Type holderType, string? fieldName) - => $"[Error] Invalid instanceID '{fieldName.ValueOrNull()}' for '{holderType.GetTypeName(pretty: false)}'. It should be a valid field name."; + => $"[Error] Invalid instanceID '{fieldName.ValueOrNull()}' for '{holderType.GetTypeId()}'. It should be a valid field name."; public static string InvalidPropertyType(SerializedMember serializedProperty, PropertyInfo propertyInfo) - => $"[Error] Invalid property type '{serializedProperty.typeName.ValueOrNull()}' for '{propertyInfo.Name}'. Expected '{propertyInfo.PropertyType.GetTypeName(pretty: false)}' or extended from it."; + => $"[Error] Invalid property type '{serializedProperty.typeName.ValueOrNull()}' for '{propertyInfo.Name}'. Expected '{propertyInfo.PropertyType.GetTypeId()}' or extended from it."; public static string InvalidFieldType(SerializedMember serializedProperty, FieldInfo propertyInfo) - => $"[Error] Invalid field type '{serializedProperty.typeName.ValueOrNull()}' for '{propertyInfo.Name}'. Expected '{propertyInfo.FieldType.GetTypeName(pretty: false)}' or extended from it."; + => $"[Error] Invalid field type '{serializedProperty.typeName.ValueOrNull()}' for '{propertyInfo.Name}'. Expected '{propertyInfo.FieldType.GetTypeId()}' or extended from it."; public static string NotSupportedInRuntime(Type type) - => $"[Error] Type '{type.GetTypeName(pretty: false).ValueOrNull()}' is not supported in runtime for now."; + => $"[Error] Type '{type.GetTypeId().ValueOrNull()}' is not supported in runtime for now."; public static string MoreThanOneMethodFound(Reflector reflector, List methods) { diff --git a/ReflectorNet/src/Reflector/Reflector.FindMethod.cs b/ReflectorNet/src/Reflector/Reflector.FindMethod.cs index fab0efa3..27653a1f 100644 --- a/ReflectorNet/src/Reflector/Reflector.FindMethod.cs +++ b/ReflectorNet/src/Reflector/Reflector.FindMethod.cs @@ -100,7 +100,7 @@ static int Compare(ParameterInfo[] original, List? value) if (parameter.Name != methodRefParameter.Name) return 1; - if (parameter.ParameterType.GetTypeName(pretty: false) != methodRefParameter.TypeName) + if (parameter.ParameterType.GetTypeId() != methodRefParameter.TypeName) return 1; } diff --git a/ReflectorNet/src/Reflector/Reflector.Populate.cs b/ReflectorNet/src/Reflector/Reflector.Populate.cs index 5ba0454c..17ea5436 100644 --- a/ReflectorNet/src/Reflector/Reflector.Populate.cs +++ b/ReflectorNet/src/Reflector/Reflector.Populate.cs @@ -60,9 +60,9 @@ public bool TryPopulate( if (converter == null) { if (logger?.IsEnabled(LogLevel.Error) == true) - logger.LogError($"{padding}No suitable converter found for type {objType.GetTypeName(pretty: false)}"); + logger.LogError($"{padding}No suitable converter found for type '{objType.GetTypeId()}'"); - logs?.Error($"No suitable converter found for type {objType.GetTypeName(pretty: false)}", depth); + logs?.Error($"No suitable converter found for type '{objType.GetTypeId()}'", depth); return false; } diff --git a/ReflectorNet/src/Reflector/Reflector.cs b/ReflectorNet/src/Reflector/Reflector.cs index 4cecc5b3..2813935f 100644 --- a/ReflectorNet/src/Reflector/Reflector.cs +++ b/ReflectorNet/src/Reflector/Reflector.cs @@ -109,7 +109,7 @@ public SerializedMember Serialize( var converter = Converters.GetConverter(type); if (converter == null) - throw new ArgumentException($"[Error] Type '{type.GetTypeName(pretty: false).ValueOrNull()}' not supported for serialization."); + throw new ArgumentException($"Type '{type.GetTypeId().ValueOrNull()}' not supported for serialization."); if (logger?.IsEnabled(LogLevel.Trace) == true) logger.LogTrace($"{StringUtils.GetPadding(depth)} Serialize. {converter.GetType().GetTypeShortName()} used for type='{type.GetTypeShortName()}', name='{name.ValueOrNull()}'"); @@ -241,7 +241,7 @@ public SerializedMember Serialize( var converter = Converters.GetConverter(type); if (converter == null) - throw new ArgumentException($"[Error] Type '{type?.GetTypeName(pretty: false).ValueOrNull()}' not supported for deserialization."); + throw new ArgumentException($"[Error] Type '{type?.GetTypeId().ValueOrNull()}' not supported for deserialization."); if (logger?.IsEnabled(LogLevel.Trace) == true) logger.LogTrace($"{padding}{Consts.Emoji.Launch} Deserialize type='{type.GetTypeShortName()}' name='{name.ValueOrNull()}' converter='{converter.GetType().GetTypeShortName()}'"); diff --git a/ReflectorNet/src/Utils/Json/JsonSchema.cs b/ReflectorNet/src/Utils/Json/JsonSchema.cs index e53ab77b..4bd12f47 100644 --- a/ReflectorNet/src/Utils/Json/JsonSchema.cs +++ b/ReflectorNet/src/Utils/Json/JsonSchema.cs @@ -163,7 +163,7 @@ public JsonNode GetSchema(Reflector reflector, Type type, JsonObject? defines = { var genericArgs = TypeUtils.GetDictionaryGenericArguments(type); if (genericArgs == null) - throw new InvalidOperationException($"Unable to get generic arguments for dictionary type '{type.GetTypeName(pretty: false)}'."); + throw new InvalidOperationException($"Unable to get generic arguments for dictionary type '{type.GetTypeId()}'."); foreach (var genericArgument in genericArgs) { @@ -222,12 +222,12 @@ public JsonNode GetSchema(Reflector reflector, Type type, JsonObject? defines = // Handle exceptions and return null or an error message return new JsonObject() { - [Error] = $"Failed to get schema for '{type.GetTypeName(pretty: false)}':\n{ex.Message}\n{ex.StackTrace}\n" + [Error] = $"Failed to get schema for '{type.GetTypeId()}':\n{ex.Message}\n{ex.StackTrace}\n" }; } if (schema == null) - throw new InvalidOperationException($"Failed to get schema for type '{type.GetTypeName(pretty: false)}'."); + throw new InvalidOperationException($"Failed to get schema for type '{type.GetTypeId()}'."); PostprocessFields(schema); @@ -235,7 +235,7 @@ public JsonNode GetSchema(Reflector reflector, Type type, JsonObject? defines = { return new JsonObject() { - [Error] = $"Unexpected schema type for '{type.GetTypeName(pretty: false)}'. Json Schema type: {schema.GetType().GetTypeName()}" + [Error] = $"Unexpected schema type for '{type.GetTypeId()}'. Json Schema type: {schema.GetType().GetTypeId()}" }; } return schema; @@ -298,12 +298,12 @@ public JsonNode GetSchemaRef(Reflector reflector, Type type) // Handle exceptions and return null or an error message return new JsonObject() { - [Error] = $"Failed to get schema for '{type.GetTypeName(pretty: false)}':\n{ex.Message}\n{ex.StackTrace}\n" + [Error] = $"Failed to get schema for '{type.GetTypeId()}':\n{ex.Message}\n{ex.StackTrace}\n" }; } if (schema == null) - throw new InvalidOperationException($"Failed to get schema for type '{type.GetTypeName(pretty: false)}'."); + throw new InvalidOperationException($"Failed to get schema for type '{type.GetTypeId()}'."); PostprocessFields(schema); @@ -311,7 +311,7 @@ public JsonNode GetSchemaRef(Reflector reflector, Type type) { return new JsonObject() { - [Error] = $"Unexpected schema type for '{type.GetTypeName(pretty: false)}'. Json Schema type: {schema.GetType().GetTypeName()}" + [Error] = $"Unexpected schema type for '{type.GetTypeId()}'. Json Schema type: {schema.GetType().GetTypeId()}" }; } return schema; diff --git a/ReflectorNet/src/Utils/Print/Print.cs b/ReflectorNet/src/Utils/Print/Print.cs index 0d442f9a..35b67154 100644 --- a/ReflectorNet/src/Utils/Print/Print.cs +++ b/ReflectorNet/src/Utils/Print/Print.cs @@ -18,7 +18,7 @@ public static class Print { public static void FailedToSetNewValue(ref object? obj, Type type, int depth = 0, Logs? logs = null, ILogger? logger = null) { - logs?.Error($"Failed to set new value for '{type.GetTypeName(pretty: false)}'.", depth); + logs?.Error($"Failed to set new value for '{type.GetTypeId()}'.", depth); } public static void SetNewValue(ref object? obj, ref T? newValue, Type type, int depth = 0, Logs? logs = null, ILogger? logger = null) { @@ -26,8 +26,8 @@ public static void SetNewValue(ref object? obj, ref T? newValue, Type type, i var newType = newValue?.GetType() ?? type; logs?.Success($@"Set value - was: type='{originalType.GetTypeName(pretty: false).ValueOrNull()}', value='{obj}' - new: type='{newType.GetTypeName(pretty: false).ValueOrNull()}', value='{newValue}'.", depth); + was: type='{originalType.GetTypeId().ValueOrNull()}', value='{obj}' + new: type='{newType.GetTypeId().ValueOrNull()}', value='{newValue}'.", depth); } public static void SetNewValueEnumerable(ref object? obj, ref IEnumerable? newValue, Type type, int depth = 0, Logs? logs = null, ILogger? logger = null) { @@ -35,8 +35,8 @@ public static void SetNewValueEnumerable(ref object? obj, ref IEnumerable? newVa var newType = newValue?.GetType() ?? type; logs?.Success($@"Set array value - was: type='{originalType.GetTypeName(pretty: false).ValueOrNull()}', value='{obj}' - new: type='{newType.GetTypeName(pretty: false).ValueOrNull()}', value='{newValue}'.", depth); + was: type='{originalType.GetTypeId().ValueOrNull()}', value='{obj}' + new: type='{newType.GetTypeId().ValueOrNull()}', value='{newValue}'.", depth); } public static void SetNewValueEnumerable(ref object? obj, ref IEnumerable? newValue, Type type, int depth = 0, Logs? logs = null, ILogger? logger = null) { @@ -44,18 +44,18 @@ public static void SetNewValueEnumerable(ref object? obj, ref IEnumerable? var newType = newValue?.GetType() ?? type; logs?.Success($@"Set array value - was: type='{originalType.GetTypeName(pretty: false).ValueOrNull()}', value='{obj}' - new: type='{newType.GetTypeName(pretty: false).ValueOrNull()}', value='{newValue}'.", depth); + was: type='{originalType.GetTypeId().ValueOrNull()}', value='{obj}' + new: type='{newType.GetTypeId().ValueOrNull()}', value='{newValue}'.", depth); } public static void FailedToSetField(ref object? obj, Type type, FieldInfo fieldInfo, int depth = 0, Logs? logs = null, ILogger? logger = null) { logs?.Error($"Failed to set field '{fieldInfo.Name}'", depth); - logs?.Error($"Failed to set new value for '{type.GetTypeName(pretty: false)}'.", depth); + logs?.Error($"Failed to set new value for '{type.GetTypeId()}'.", depth); } public static void FailedToSetProperty(ref object? obj, Type type, PropertyInfo propertyInfo, int depth = 0, Logs? logs = null, ILogger? logger = null) { logs?.Error($"Failed to set property '{propertyInfo.Name}'", depth); - logs?.Error($"Failed to set new value for '{type.GetTypeName(pretty: false)}'.", depth); + logs?.Error($"Failed to set new value for '{type.GetTypeId()}'.", depth); } } } \ No newline at end of file diff --git a/ReflectorNet/src/Utils/StringUtils.cs b/ReflectorNet/src/Utils/StringUtils.cs index 7aca41a1..ef1cc2a5 100644 --- a/ReflectorNet/src/Utils/StringUtils.cs +++ b/ReflectorNet/src/Utils/StringUtils.cs @@ -104,16 +104,16 @@ public static bool Path_ParseParent(string? path, out string? parentPath, out st else { throw new ArgumentException( - $"Value '{stringValue}' for parameter '{parameterName}' was parsed but is not a defined member of '{enumType.GetTypeName(pretty: true)}'. Valid values are: {string.Join(", ", Enum.GetNames(enumType))}"); + $"Value '{stringValue}' for parameter '{parameterName}' was parsed but is not a defined member of '{enumType.GetTypeId()}'. Valid values are: {string.Join(", ", Enum.GetNames(enumType))}"); } } else { throw new ArgumentException( - $"Value '{stringValue}' for parameter '{parameterName}' could not be parsed as '{enumType.GetTypeName(pretty: true)}'. Valid values are: {string.Join(", ", Enum.GetNames(enumType))}"); + $"Value '{stringValue}' for parameter '{parameterName}' could not be parsed as '{enumType.GetTypeId()}'. Valid values are: {string.Join(", ", Enum.GetNames(enumType))}"); } } - throw new ArgumentException($"Parameter '{parameterName}' type mismatch. Expected '{enumType.GetTypeName(pretty: true)}', but got '{value?.GetType()}'."); + throw new ArgumentException($"Parameter '{parameterName}' type mismatch. Expected '{enumType.GetTypeId()}', but got '{value?.GetType()}'."); } } } \ No newline at end of file diff --git a/ReflectorNet/src/Utils/TypeUtils.Name.cs b/ReflectorNet/src/Utils/TypeUtils.Name.cs index a8aab145..ef0c44e3 100644 --- a/ReflectorNet/src/Utils/TypeUtils.Name.cs +++ b/ReflectorNet/src/Utils/TypeUtils.Name.cs @@ -6,10 +6,21 @@ namespace com.IvanMurzak.ReflectorNet.Utils { public static partial class TypeUtils { - public const string ArraySuffix = "_Array"; + public const string ArraySuffix = "[]"; - public static string GetTypeName(bool pretty = false) => GetTypeName(typeof(T), pretty); - public static string GetTypeName(Type? type, bool pretty = false) + /// + /// Returns the sanitized type name. + /// 1. Unwraps nullable types. + /// 2. Returns FullName. + /// + public static string Sanitize() => Sanitize(typeof(T)); + + /// + /// Returns the sanitized type name. + /// 1. Unwraps nullable types. + /// 2. Returns FullName. + /// + public static string Sanitize(Type? type) { if (type == null) return StringUtils.Null; @@ -17,9 +28,7 @@ public static string GetTypeName(Type? type, bool pretty = false) // Handle nullable types type = Nullable.GetUnderlyingType(type) ?? type; - return pretty - ? type.FullName ?? StringUtils.Null - : type.AssemblyQualifiedName ?? StringUtils.Null; + return type.FullName ?? StringUtils.Null; } public static string GetTypeId() => GetTypeId(typeof(T)); public static string GetTypeId(Type type) @@ -27,75 +36,58 @@ public static string GetTypeId(Type type) if (type == null) throw new ArgumentNullException(nameof(type)); + if (type.IsGenericParameter) + return type.Name; + // Handle nullable types type = Nullable.GetUnderlyingType(type) ?? type; // Special case: string is technically IEnumerable but shouldn't be treated as an array if (type == typeof(string)) - return GetTypeName(type, pretty: true); + return Sanitize(type); - // If type is a generic type, use its full name with generic arguments - if (type.IsGenericType) + if (type.IsNested) { - var genericTypeName = type.GetGenericTypeDefinition().GetTypeName(pretty: true); - if (StringUtils.IsNullOrEmpty(genericTypeName)) - throw new InvalidOperationException($"Generic type '{type}' does not have a full name."); + var declaringType = type.DeclaringType; + if (declaringType != null) + { + if (declaringType.IsGenericTypeDefinition && type.IsGenericType && !type.IsGenericTypeDefinition) + { + var allArgs = type.GetGenericArguments(); + var declArgs = declaringType.GetGenericArguments(); + if (allArgs.Length >= declArgs.Length) + { + var properDeclArgs = allArgs.Take(declArgs.Length).ToArray(); + declaringType = declaringType.MakeGenericType(properDeclArgs); + } + } - var tickIndex = genericTypeName.IndexOf('`'); - if (tickIndex > 0) - genericTypeName = genericTypeName.Substring(0, tickIndex); + var declaringTypeId = GetTypeId(declaringType); + var name = type.Name; + var tickIndex = name.IndexOf('`'); + if (tickIndex > 0) + name = name.Substring(0, tickIndex); - // Recursively get the type ID for each generic argument - var genericArgs = type.GetGenericArguments().Select(GetTypeId); - return $"{genericTypeName}<{string.Join(",", genericArgs)}>"; - } + if (type.IsGenericType) + { + var totalArgs = type.GetGenericArguments(); + var outerArgsCount = declaringType.IsGenericType ? declaringType.GetGenericArguments().Length : 0; + + if (totalArgs.Length > outerArgsCount) + { + var localArgs = totalArgs.Skip(outerArgsCount).Select(GetTypeId); + return $"{declaringTypeId}+{name}<{string.Join(",", localArgs)}>"; + } + } - if (type.IsArray) - { - var elementType = type.GetElementType(); - if (elementType == null) - throw new InvalidOperationException($"Array type '{type}' has no element type."); - return $"{GetTypeId(elementType)}{ArraySuffix}"; + return $"{declaringTypeId}+{name}"; + } } - return GetTypeName(type, pretty: true); - } - - public static string GetSchemaTypeId() => GetSchemaTypeId(typeof(T)); - public static string GetSchemaTypeId(Type type) - { - if (type == null) - throw new ArgumentNullException(nameof(type)); - - // Handle nullable types - type = Nullable.GetUnderlyingType(type) ?? type; - - // Special case: string is technically IEnumerable but shouldn't be treated as an array - if (type == typeof(string)) - return GetTypeName(type, pretty: true); - // If type is a generic type, use its full name with generic arguments if (type.IsGenericType) { - var genericTypes = type.GetGenericArguments(); - if (genericTypes.Length == 1) - { - if (typeof(System.Collections.IList).IsAssignableFrom(type) || - typeof(ISet<>).MakeGenericType(genericTypes).IsAssignableFrom(type) || - typeof(LinkedList<>).MakeGenericType(genericTypes).IsAssignableFrom(type) || - typeof(Queue<>).MakeGenericType(genericTypes).IsAssignableFrom(type) || - typeof(Stack<>).MakeGenericType(genericTypes).IsAssignableFrom(type) || - typeof(List<>).MakeGenericType(genericTypes).IsAssignableFrom(type) || - typeof(SortedSet<>).MakeGenericType(genericTypes).IsAssignableFrom(type)) - { - var itemType = genericTypes[0]; - if (itemType == null) - throw new InvalidOperationException($"Array type '{type}' has no item type."); - return $"{GetSchemaTypeId(itemType)}{ArraySuffix}"; - } - } - - var genericTypeName = type.GetGenericTypeDefinition().GetTypeName(pretty: true); + var genericTypeName = type.GetGenericTypeDefinition().Sanitize(); if (StringUtils.IsNullOrEmpty(genericTypeName)) throw new InvalidOperationException($"Generic type '{type}' does not have a full name."); @@ -104,7 +96,7 @@ public static string GetSchemaTypeId(Type type) genericTypeName = genericTypeName.Substring(0, tickIndex); // Recursively get the type ID for each generic argument - var genericArgs = genericTypes.Select(GetSchemaTypeId); + var genericArgs = type.GetGenericArguments().Select(GetTypeId); return $"{genericTypeName}<{string.Join(",", genericArgs)}>"; } @@ -113,20 +105,27 @@ public static string GetSchemaTypeId(Type type) var elementType = type.GetElementType(); if (elementType == null) throw new InvalidOperationException($"Array type '{type}' has no element type."); - return $"{GetSchemaTypeId(elementType)}{ArraySuffix}"; + + var rank = type.GetArrayRank(); + if (rank == 1) + return $"{GetTypeId(elementType)}{ArraySuffix}"; + + return $"{GetTypeId(elementType)}[{new string(',', rank - 1)}]"; } - return GetTypeName(type, pretty: true); + return Sanitize(type); } + public static string GetSchemaTypeId() => GetTypeId(typeof(T)); + public static string GetSchemaTypeId(Type type) => GetTypeId(type); + public static bool IsNameMatch(Type? type, string? typeName) { if (type == null || string.IsNullOrEmpty(typeName)) return false; // Check if the type name matches the full name of the type - return type.GetTypeName(pretty: true) == typeName || - type.GetTypeName(pretty: false) == typeName; + return type.GetTypeId() == typeName; } @@ -145,11 +144,52 @@ public static string GetTypeShortName(Type? type) if (type == null) return StringUtils.Null; + if (type.IsGenericParameter) + return type.Name; + // Handle nullable types var underlyingNullableType = Nullable.GetUnderlyingType(type); if (underlyingNullableType != null) return $"{GetTypeShortName(underlyingNullableType)}?"; + if (type.IsNested) + { + var declaringType = type.DeclaringType; + if (declaringType != null) + { + if (declaringType.IsGenericTypeDefinition && type.IsGenericType && !type.IsGenericTypeDefinition) + { + var allArgs = type.GetGenericArguments(); + var declArgs = declaringType.GetGenericArguments(); + if (allArgs.Length >= declArgs.Length) + { + var properDeclArgs = allArgs.Take(declArgs.Length).ToArray(); + declaringType = declaringType.MakeGenericType(properDeclArgs); + } + } + + var declaringTypeName = GetTypeShortName(declaringType); + var name = type.Name; + var tickIndex = name.IndexOf('`'); + if (tickIndex > 0) + name = name.Substring(0, tickIndex); + + if (type.IsGenericType) + { + var totalArgs = type.GetGenericArguments(); + var outerArgsCount = declaringType.IsGenericType ? declaringType.GetGenericArguments().Length : 0; + + if (totalArgs.Length > outerArgsCount) + { + var localArgs = totalArgs.Skip(outerArgsCount).Select(GetTypeShortName); + return $"{declaringTypeName}+{name}<{string.Join(", ", localArgs)}>"; + } + } + + return $"{declaringTypeName}+{name}"; + } + } + if (type.IsGenericType) { var genericTypeName = type.Name; @@ -163,10 +203,14 @@ public static string GetTypeShortName(Type? type) if (type.IsArray) { var elementType = type.GetElementType(); - return $"{GetTypeShortName(elementType)}[]"; + var rank = type.GetArrayRank(); + if (rank == 1) + return $"{GetTypeShortName(elementType)}[]"; + + return $"{GetTypeShortName(elementType)}[{new string(',', rank - 1).Replace(",", ", ")}]"; } return string.IsNullOrEmpty(type.Name) ? StringUtils.Null : type.Name; } } -} \ No newline at end of file +} diff --git a/ReflectorNet/src/Utils/TypeUtils.cs b/ReflectorNet/src/Utils/TypeUtils.cs index 1382962f..dbb0adc4 100644 --- a/ReflectorNet/src/Utils/TypeUtils.cs +++ b/ReflectorNet/src/Utils/TypeUtils.cs @@ -6,6 +6,7 @@ */ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; using System.Linq; @@ -19,24 +20,455 @@ public static partial class TypeUtils public static IEnumerable AllTypes => AppDomain.CurrentDomain.GetAssemblies() .SelectMany(assembly => assembly.GetTypes()); + // Cache for resolved type names to avoid repeated AllTypes enumeration (thread-safe) + private static readonly ConcurrentDictionary _typeCache = new ConcurrentDictionary(); + public static Type? GetType(string? typeName) { if (string.IsNullOrWhiteSpace(typeName)) return null; + // Check cache first + if (_typeCache.TryGetValue(typeName, out var cachedType)) + return cachedType; + // First try built-in Type.GetType() which handles many formats - var type = Type.GetType(typeName, throwOnError: false); + Type? type = null; + try + { + type = Type.GetType(typeName, throwOnError: false); + } + catch + { + // Ignore exceptions (e.g. invalid assembly name) and try other resolution methods + } + + if (type != null) + { + _typeCache[typeName] = type; + return type; + } + + // Try resolving array types (e.g., "Namespace.Type[]") + type = TryResolveArrayType(typeName); if (type != null) + { + _typeCache[typeName] = type; + return type; + } + + // Try resolving C#-style generic types (e.g., "Namespace.Generic" or "Namespace.Generic") + type = TryResolveCSharpGenericType(typeName); + if (type != null) + { + _typeCache[typeName] = type; return type; + } + + // Try resolving generic types (e.g., "Namespace.Generic`1[[TypeArg]]") + type = TryResolveClassicGenericType(typeName); + if (type != null) + { + _typeCache[typeName] = type; + return type; + } // If Type.GetType() fails, try to find the type in all loaded assemblies type = AllTypes.FirstOrDefault(t => typeName == t.FullName || - typeName == t.AssemblyQualifiedName); + typeName == t.AssemblyQualifiedName || + typeName == t.GetTypeId()); + + // Caching the result (even if null) + _typeCache[typeName] = type; return type; } + /// + /// Attempts to resolve a simple (non-generic, non-array) type by name. + /// + private static Type? ResolveSimpleType(string name) + { + var type = Type.GetType(name, throwOnError: false); + if (type != null) + return type; + + return AllTypes.FirstOrDefault(t => + name == t.AssemblyQualifiedName || + name == t.FullName || + name == t.Name); + } + + /// + /// Attempts to resolve array type names (e.g., "Namespace.Type[]"). + /// + private static Type? TryResolveArrayType(string typeName) + { + if (!typeName.EndsWith("]")) + return null; + + var lastOpenBracket = typeName.LastIndexOf('['); + if (lastOpenBracket < 0) + return null; + + var suffix = typeName.Substring(lastOpenBracket); + // Check if content contains only commas + var content = suffix.Substring(1, suffix.Length - 2); + if (content.Length > 0 && content.Any(c => c != ',')) + return null; + + var commas = content.Length; + var elementTypeName = typeName.Substring(0, lastOpenBracket); + var elementType = GetType(elementTypeName); + + if (elementType == null) return null; + + return commas == 0 + ? elementType.MakeArrayType() + : elementType.MakeArrayType(commas + 1); + } + + /// + /// Attempts to resolve C#-style generic types. + /// Handles formats like: "Namespace.Generic<TypeArg>" or "Namespace.Generic<TypeArg1, TypeArg2>" + /// Also handles nested types: "Namespace.Generic<TypeArg>+Nested" or "Namespace.Generic<TypeArg>+Nested<TypeArg2>" + /// Space after comma is optional. + /// + private static Type? TryResolveCSharpGenericType(string typeName) + { + // Find the opening angle bracket + var openBracketIndex = typeName.IndexOf('<'); + if (openBracketIndex < 0) + return null; + + // Find the matching closing angle bracket + var closeBracketIndex = FindMatchingCloseBracket(typeName, openBracketIndex); + if (closeBracketIndex < 0) + return null; + + // Extract the base type name (everything before '<') + var baseTypeName = typeName.Substring(0, openBracketIndex); + if (string.IsNullOrWhiteSpace(baseTypeName)) + return null; + + // Extract the type arguments string (between '<' and '>') + var typeArgsString = typeName.Substring(openBracketIndex + 1, closeBracketIndex - openBracketIndex - 1); + + // Parse the type arguments + var typeArgNames = ParseCSharpGenericArguments(typeArgsString); + if (typeArgNames == null || typeArgNames.Length == 0) + return null; + + // Construct the generic type definition name (e.g., "Namespace.Generic`2") + var genericDefName = $"{baseTypeName}`{typeArgNames.Length}"; + + // Resolve the generic type definition + var genericDef = ResolveSimpleType(genericDefName); + if (genericDef == null || !genericDef.IsGenericTypeDefinition) + return null; + + // Resolve each type argument + var typeArgs = new Type[typeArgNames.Length]; + for (int i = 0; i < typeArgNames.Length; i++) + { + var argType = GetType(typeArgNames[i].Trim()); + if (argType == null) + return null; + typeArgs[i] = argType; + } + + Type? currentType; + try + { + currentType = genericDef.MakeGenericType(typeArgs); + } + catch + { + return null; + } + + // Handle nested types appended after the generic arguments + var remaining = typeName.Substring(closeBracketIndex + 1); + while (!string.IsNullOrEmpty(remaining)) + { + if (!remaining.StartsWith("+") && !remaining.StartsWith(".")) + return null; + + remaining = remaining.Substring(1); // Remove separator + + // Check for generic args + var open = remaining.IndexOf('<'); + string nestedName; + Type[]? nestedArgs = null; + int nextRemainingIndex; + + if (open > 0) + { + var close = FindMatchingCloseBracket(remaining, open); + if (close < 0) return null; + + nestedName = remaining.Substring(0, open); + var argsStr = remaining.Substring(open + 1, close - open - 1); + var argNames = ParseCSharpGenericArguments(argsStr); + if (argNames == null) return null; + + nestedArgs = new Type[argNames.Length]; + for (int i = 0; i < argNames.Length; i++) + { + var tempType = GetType(argNames[i]?.Trim()); + if (tempType == null) return null; + nestedArgs[i] = tempType; + } + + nextRemainingIndex = close + 1; + } + else + { + // No generic args, but check if there are more separators + var nextSep = remaining.IndexOfAny(new[] { '+', '.' }); + if (nextSep > 0) + { + nestedName = remaining.Substring(0, nextSep); + nextRemainingIndex = nextSep; + } + else + { + nestedName = remaining; + nextRemainingIndex = remaining.Length; + } + } + + // Find nested type + Type? nestedType; + Type[] allArgs; + + if (nestedArgs != null) + { + nestedType = currentType.GetNestedType($"{nestedName}`{nestedArgs.Length}"); + if (nestedType == null) return null; + + if (currentType.IsGenericType && !currentType.IsGenericTypeDefinition) + { + var parentArgs = currentType.GetGenericArguments(); + allArgs = new Type[parentArgs.Length + nestedArgs.Length]; + Array.Copy(parentArgs, allArgs, parentArgs.Length); + Array.Copy(nestedArgs, 0, allArgs, parentArgs.Length, nestedArgs.Length); + } + else + { + allArgs = nestedArgs; + } + } + else + { + nestedType = currentType.GetNestedType(nestedName); + if (nestedType == null) return null; + + allArgs = currentType.IsGenericType && !currentType.IsGenericTypeDefinition + ? currentType.GetGenericArguments() + : Type.EmptyTypes; + } + + if (nestedType.IsGenericTypeDefinition) + { + try + { + currentType = nestedType.GetGenericArguments().Length == allArgs.Length + ? nestedType.MakeGenericType(allArgs) + : nestedType; + } + catch + { + return null; + } + } + else + { + currentType = nestedType; + } + + remaining = remaining.Substring(nextRemainingIndex); + } + + return currentType; + } + + /// + /// Finds the matching closing angle bracket for an opening bracket. + /// Handles nested generic types properly. + /// + private static int FindMatchingCloseBracket(string typeName, int openIndex) + { + var depth = 0; + for (int i = openIndex; i < typeName.Length; i++) + { + if (typeName[i] == '<') + depth++; + else if (typeName[i] == '>') + { + depth--; + if (depth == 0) + return i; + } + } + return -1; + } + + /// + /// Parses C#-style generic arguments from a string like "TypeArg1, TypeArg2" or "List<int>, string". + /// Handles nested generic types by tracking bracket depth. + /// + private static string[]? ParseCSharpGenericArguments(string argsString) + { + if (string.IsNullOrWhiteSpace(argsString)) + return null; + + var args = new List(); + var depth = 0; + var currentArg = new System.Text.StringBuilder(); + + for (int i = 0; i < argsString.Length; i++) + { + var c = argsString[i]; + + if (c == '<') + { + depth++; + currentArg.Append(c); + } + else if (c == '>') + { + depth--; + currentArg.Append(c); + } + else if (c == ',' && depth == 0) + { + // Top-level comma - separator between type arguments + var arg = currentArg.ToString().Trim(); + if (!string.IsNullOrEmpty(arg)) + args.Add(arg); + currentArg.Clear(); + } + else + { + currentArg.Append(c); + } + } + + // Add the last argument + var lastArg = currentArg.ToString().Trim(); + if (!string.IsNullOrEmpty(lastArg)) + args.Add(lastArg); + + return args.Count > 0 ? args.ToArray() : null; + } + + /// + /// Attempts to resolve constructed generic types by parsing and reconstructing them. + /// Handles formats like: "Namespace.Generic`1[[TypeArg, Assembly]]" + /// + private static Type? TryResolveClassicGenericType(string typeName) + { + // Find generic arity marker (backtick) + var backtickIndex = typeName.IndexOf('`'); + if (backtickIndex < 0) + return null; + + // Find the start of generic arguments [[...]] + var argsStart = typeName.IndexOf("[[", backtickIndex); + if (argsStart < 0) + return null; + + // Extract generic definition name (e.g., "Namespace.WrapperClass`1") + var genericDefName = typeName.Substring(0, argsStart); + + // Resolve the generic type definition + var genericDef = ResolveSimpleType(genericDefName); + if (genericDef == null || !genericDef.IsGenericTypeDefinition) + return null; + + // Parse and resolve type arguments + var typeArgs = ParseGenericArguments(typeName, argsStart); + if (typeArgs == null || typeArgs.Length != genericDef.GetGenericArguments().Length) + return null; + + try + { + return genericDef.MakeGenericType(typeArgs); + } + catch + { + return null; + } + } + + /// + /// Parses generic arguments from the [[Type1, Assembly], [Type2, Assembly]] format. + /// The format uses double brackets where: + /// - Outer [] wraps all type arguments + /// - Inner [] wraps each individual type argument + /// - Nested generic types have their own [[]] inside + /// + private static Type[]? ParseGenericArguments(string typeName, int startIndex) + { + var args = new List(); + var depth = 0; + var currentArg = new System.Text.StringBuilder(); + + for (int i = startIndex; i < typeName.Length; i++) + { + var c = typeName[i]; + + if (c == '[') + { + depth++; + // Only append brackets for nested generics (depth > 2) + // depth 1 = outer wrapper for all args + // depth 2 = wrapper for individual type arg (don't include) + // depth 3+ = nested generic brackets (include) + if (depth > 2) + currentArg.Append(c); + } + else if (c == ']') + { + depth--; + if (depth == 1) + { + // End of one type argument + var argTypeName = currentArg.ToString().Trim(); + if (!string.IsNullOrEmpty(argTypeName)) + { + var argType = GetType(argTypeName); + if (argType == null) + return null; + args.Add(argType); + } + currentArg.Clear(); + } + else if (depth > 1) + { + // Append closing brackets for nested generics + currentArg.Append(c); + } + else if (depth == 0) + { + break; // End of all arguments + } + } + else if (c == ',' && depth == 1) + { + // Separator between type arguments at the top level - skip it + } + else if (depth > 1) + { + currentArg.Append(c); + } + } + + return args.Count > 0 ? args.ToArray() : null; + } + public static bool IsDictionary(Type type) { if (type.IsGenericType && @@ -393,4 +825,4 @@ public static bool IsIEnumerable(Type type) return type; } } -} \ No newline at end of file +} diff --git a/TestShortName.cs b/TestShortName.cs new file mode 100644 index 00000000..ef37869b --- /dev/null +++ b/TestShortName.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using com.IvanMurzak.ReflectorNet.Utils; + +namespace TestNamespace +{ + public class Outer + { + public class Nested { } + } +} + +public class Program +{ + public static void Main() + { + var type = typeof(TestNamespace.Outer.Nested); + Console.WriteLine($"Type: {type.FullName}"); + Console.WriteLine($"Type.Name: {type.Name}"); + Console.WriteLine($"IsGenericType: {type.IsGenericType}"); + Console.WriteLine($"GenericArgs: {string.Join(", ", type.GetGenericArguments().Select(t => t.Name))}"); + + // Simulate GetTypeShortName logic + Console.WriteLine($"ShortName: {TypeUtils.GetTypeShortName(type)}"); + } +}