Skip to content

Commit 6190c3a

Browse files
authored
Merge pull request #59 from IvanMurzak/update/reflection-converter-interface-properties
feat: enhance IReflectionConverter interface with cascading conversion properties
2 parents 14bb137 + d0366c2 commit 6190c3a

4 files changed

Lines changed: 82 additions & 22 deletions

File tree

ReflectorNet.Tests/src/ReflectorTests/LazyReflectionConverterTests.cs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public void SerializationPriority_TypeExists_ReturnsHighPriority()
4141
{
4242
// Arrange
4343
var typeName = typeof(TestTarget).FullName!;
44-
var converter = new LazyReflectionConverter(typeName);
44+
var converter = new LazyGenericReflectionConverter(typeName);
4545

4646
// Act
4747
var priority = converter.SerializationPriority(typeof(TestTarget));
@@ -56,7 +56,7 @@ public void SerializationPriority_TypeDoesNotExist_ReturnsZero()
5656
{
5757
// Arrange
5858
var typeName = "System.NonExistentType.ShouldNotExist";
59-
var converter = new LazyReflectionConverter(typeName);
59+
var converter = new LazyGenericReflectionConverter(typeName);
6060

6161
// Act
6262
var priority = converter.SerializationPriority(typeof(TestTarget));
@@ -71,7 +71,7 @@ public void SerializationPriority_DerivedType_ReturnsPositivePriority()
7171
{
7272
// Arrange
7373
var typeName = typeof(TestTarget).FullName!;
74-
var converter = new LazyReflectionConverter(typeName);
74+
var converter = new LazyGenericReflectionConverter(typeName);
7575

7676
// Act
7777
var exactMatchPriority = converter.SerializationPriority(typeof(TestTarget));
@@ -90,7 +90,7 @@ public void Serialize_IgnoresConfiguredProperties()
9090
// Arrange
9191
var typeName = typeof(TestTarget).FullName!;
9292
var ignoredProps = new[] { "Secret" };
93-
var converter = new LazyReflectionConverter(typeName, ignoredProperties: ignoredProps);
93+
var converter = new LazyGenericReflectionConverter(typeName, ignoredProperties: ignoredProps);
9494
var reflector = new Reflector();
9595

9696
// Register manually to ensure it's used
@@ -119,7 +119,7 @@ public void Serialize_IgnoresConfiguredFields()
119119
// Arrange
120120
var typeName = typeof(TestTargetWithFields).FullName!;
121121
var ignoredFields = new[] { "SecretField" };
122-
var converter = new LazyReflectionConverter(typeName, ignoredFields: ignoredFields);
122+
var converter = new LazyGenericReflectionConverter(typeName, ignoredFields: ignoredFields);
123123
var reflector = new Reflector();
124124

125125
// Register manually to ensure it's used
@@ -145,9 +145,9 @@ public void Serialize_IgnoresConfiguredFields()
145145
[Fact]
146146
public void Constructor_NullOrEmptyTypeName_ThrowsArgumentException()
147147
{
148-
Assert.Throws<ArgumentException>(() => new LazyReflectionConverter(null!));
149-
Assert.Throws<ArgumentException>(() => new LazyReflectionConverter(""));
150-
Assert.Throws<ArgumentException>(() => new LazyReflectionConverter(" "));
148+
Assert.Throws<ArgumentException>(() => new LazyGenericReflectionConverter(null!));
149+
Assert.Throws<ArgumentException>(() => new LazyGenericReflectionConverter(""));
150+
Assert.Throws<ArgumentException>(() => new LazyGenericReflectionConverter(" "));
151151
}
152152

153153
[Fact]
@@ -156,7 +156,7 @@ public void Serialize_DelegatesToBackingConverter()
156156
// Arrange
157157
var typeName = typeof(TestTarget).FullName!;
158158
var mockConverter = new MockConverter();
159-
var converter = new LazyReflectionConverter(typeName, backingConverter: mockConverter);
159+
var converter = new LazyGenericReflectionConverter(typeName, backingConverter: mockConverter);
160160
var reflector = new Reflector();
161161
reflector.Converters.Add(converter);
162162

@@ -183,7 +183,7 @@ public void Serialize_DelegatesAndFilters()
183183
var mockConverter = new MockConverter(); // Serializes everything normally because it returns all properties
184184

185185
// Should ignore "Secret" even though delegated
186-
var converter = new LazyReflectionConverter(
186+
var converter = new LazyGenericReflectionConverter(
187187
typeName,
188188
backingConverter: mockConverter,
189189
ignoredProperties: new[] { "Secret" });
@@ -210,16 +210,16 @@ public void Serialize_DelegatesAndFilters()
210210
[Fact]
211211
public void Constructor_BackingConverterWithIgnoredMembers_Succeeds()
212212
{
213-
// This verifies the fix: we no longer throw exception for this combination
214-
var typeName = typeof(TestTarget).FullName!;
215-
var mockConverter = new MockConverter();
213+
// This verifies the fix: we no longer throw exception for this combination
214+
var typeName = typeof(TestTarget).FullName!;
215+
var mockConverter = new MockConverter();
216216

217-
var converter = new LazyReflectionConverter(
218-
typeName,
219-
ignoredProperties: new[] { "Test" },
220-
backingConverter: mockConverter);
217+
var converter = new LazyGenericReflectionConverter(
218+
typeName,
219+
ignoredProperties: new[] { "Test" },
220+
backingConverter: mockConverter);
221221

222-
Assert.NotNull(converter);
222+
Assert.NotNull(converter);
223223
}
224224

225225
class MockConverter : GenericReflectionConverter<TestTarget>

ReflectorNet/ReflectorNet.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
<!-- NuGet Package Information -->
1111
<PackageId>com.IvanMurzak.ReflectorNet</PackageId>
12-
<Version>3.8.1</Version>
12+
<Version>3.9.0</Version>
1313
<Authors>Ivan Murzak</Authors>
1414
<Copyright>Copyright © Ivan Murzak 2025</Copyright>
1515
<Description>ReflectorNet is an advanced .NET reflection toolkit designed for AI-driven scenarios. Effortlessly search for C# methods using natural language queries, invoke any method by supplying arguments as JSON, and receive results as JSON. The library also provides a powerful API to inspect, modify, and manage in-memory object instances dynamically via JSON data. Ideal for automation, testing, and AI integration workflows.</Description>

ReflectorNet/src/Converter/IReflectionConverter.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,34 @@ namespace com.IvanMurzak.ReflectorNet.Converter
1515
{
1616
public interface IReflectionConverter
1717
{
18+
/// <summary>
19+
/// Gets a value indicating whether this converter supports direct value setting operations.
20+
/// When true, the converter can handle primitive-style value assignments.
21+
/// When false, the converter only supports field and property-based population.
22+
/// </summary>
23+
bool AllowSetValue { get; }
24+
25+
/// <summary>
26+
/// Gets a value indicating whether this converter supports cascading serialization operations.
27+
/// When true, nested objects and collections are recursively serialized.
28+
/// When false, only shallow serialization is performed.
29+
/// </summary>
1830
bool AllowCascadeSerialization { get; }
1931

32+
/// <summary>
33+
/// Gets a value indicating whether this converter should recursively convert field values.
34+
/// When true, field values that are complex objects are serialized recursively.
35+
/// When false, field values are serialized as simple JSON representations.
36+
/// </summary>
37+
bool AllowCascadeFieldsConversion { get; }
38+
39+
/// <summary>
40+
/// Gets a value indicating whether this converter should recursively convert property values.
41+
/// When true, property values that are complex objects are serialized recursively.
42+
/// When false, property values are serialized as simple JSON representations.
43+
/// </summary>
44+
bool AllowCascadePropertiesConversion { get; }
45+
2046
int SerializationPriority(Type type, ILogger? logger = null);
2147

2248
object? Deserialize(

ReflectorNet/src/Converter/Reflection/LazyReflectionConverter.cs renamed to ReflectorNet/src/Converter/Reflection/LazyGenericReflectionConverter.cs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,56 @@ namespace com.IvanMurzak.ReflectorNet.Converter
1818
/// This is useful for optional dependencies where the target type might not be present at runtime.
1919
/// If the type is not found, this converter will remain inactive (priority 0).
2020
/// </summary>
21-
public class LazyReflectionConverter : GenericReflectionConverter<object>
21+
public class LazyGenericReflectionConverter : LazyGenericReflectionConverter<object>
22+
{
23+
/// <summary>
24+
/// Initializes a new instance of the <see cref="LazyGenericReflectionConverter"/> class.
25+
/// </summary>
26+
/// <param name="targetTypeName">The full name of the type to handle.</param>
27+
/// <param name="ignoredProperties">Optional list of property names to ignore during serialization.</param>
28+
/// <param name="ignoredFields">Optional list of field names to ignore during serialization.</param>
29+
/// <param name="backingConverter">Optional converter to delegate serialization to.</param>
30+
public LazyGenericReflectionConverter(
31+
string targetTypeName,
32+
IEnumerable<string>? ignoredProperties = null,
33+
IEnumerable<string>? ignoredFields = null,
34+
IReflectionConverter? backingConverter = null)
35+
: base(
36+
targetTypeName: targetTypeName,
37+
ignoredProperties: ignoredProperties,
38+
ignoredFields: ignoredFields,
39+
backingConverter: backingConverter)
40+
{
41+
// empty
42+
}
43+
}
44+
45+
/// <summary>
46+
/// A reflection converter that resolves its target type lazily by name.
47+
/// This is useful for optional dependencies where the target type might not be present at runtime.
48+
/// If the type is not found, this converter will remain inactive (priority 0).
49+
/// </summary>
50+
public class LazyGenericReflectionConverter<T> : GenericReflectionConverter<T>
2251
{
2352
private readonly string _targetTypeName;
2453
private readonly HashSet<string> _ignoredProperties;
2554
private readonly HashSet<string> _ignoredFields;
2655
private readonly IReflectionConverter? _backingConverter;
2756
private readonly Lazy<Type?> _targetType;
2857

58+
public override bool AllowSetValue => _backingConverter?.AllowSetValue ?? base.AllowSetValue;
59+
public override bool AllowCascadeSerialization => _backingConverter?.AllowCascadeSerialization ?? base.AllowCascadeSerialization;
60+
public override bool AllowCascadeFieldsConversion => _backingConverter?.AllowCascadeFieldsConversion ?? base.AllowCascadeFieldsConversion;
61+
public override bool AllowCascadePropertiesConversion => _backingConverter?.AllowCascadePropertiesConversion ?? base.AllowCascadePropertiesConversion;
62+
2963
/// <summary>
30-
/// Initializes a new instance of the <see cref="LazyReflectionConverter"/> class.
64+
/// Initializes a new instance of the <see cref="LazyGenericReflectionConverter"/> class.
3165
/// </summary>
3266
/// <param name="targetTypeName">The full name of the type to handle.</param>
3367
/// <param name="ignoredProperties">Optional list of property names to ignore during serialization.</param>
3468
/// <param name="ignoredFields">Optional list of field names to ignore during serialization.</param>
3569
/// <param name="backingConverter">Optional converter to delegate serialization to.</param>
36-
public LazyReflectionConverter(
70+
public LazyGenericReflectionConverter(
3771
string targetTypeName,
3872
IEnumerable<string>? ignoredProperties = null,
3973
IEnumerable<string>? ignoredFields = null,

0 commit comments

Comments
 (0)