From fbd38c2358b3c5c9859b6aee3c0617456eb78cb0 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Sat, 10 Jan 2026 02:50:21 -0800 Subject: [PATCH 1/2] feat: Add batch blacklist methods for types and string names in Reflector --- .../ReflectorTests/IsTypeBlacklistedTests.cs | 238 ++++++++++++++++++ .../src/Reflector/Reflector.Registry.cs | 49 ++++ 2 files changed, 287 insertions(+) diff --git a/ReflectorNet.Tests/src/ReflectorTests/IsTypeBlacklistedTests.cs b/ReflectorNet.Tests/src/ReflectorTests/IsTypeBlacklistedTests.cs index 530c690..8d7cc3f 100644 --- a/ReflectorNet.Tests/src/ReflectorTests/IsTypeBlacklistedTests.cs +++ b/ReflectorNet.Tests/src/ReflectorTests/IsTypeBlacklistedTests.cs @@ -844,6 +844,244 @@ public void IsTypeBlacklisted_DeeplyDerivedFromGenericWithBlacklistedArg_Returns #endregion + #region Batch Blacklist Method Tests + + [Fact] + public void BlacklistTypes_MultipleTypes_AllAreBlacklisted() + { + // Arrange + var reflector = new Reflector(); + + // Act + reflector.Converters.BlacklistTypes( + typeof(BlacklistedBaseClass), + typeof(NonBlacklistedClass), + typeof(IBlacklistedInterface)); + + // Assert + Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(BlacklistedBaseClass))); + Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(NonBlacklistedClass))); + Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(IBlacklistedInterface))); + _output.WriteLine("All types from batch blacklist are correctly blacklisted"); + } + + [Fact] + public void BlacklistTypes_WithNullValues_IgnoresNulls() + { + // Arrange + var reflector = new Reflector(); + + // Act - Include null values which should be ignored + reflector.Converters.BlacklistTypes( + typeof(BlacklistedBaseClass), + null!, + typeof(NonBlacklistedClass)); + + // Assert + Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(BlacklistedBaseClass))); + Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(NonBlacklistedClass))); + Assert.Equal(2, reflector.Converters.GetAllBlacklistedTypes().Count); + _output.WriteLine("Null values in batch blacklist are correctly ignored"); + } + + [Fact] + public void BlacklistTypes_EmptyArray_NoChange() + { + // Arrange + var reflector = new Reflector(); + + // Act + reflector.Converters.BlacklistTypes(Array.Empty()); + + // Assert + Assert.Empty(reflector.Converters.GetAllBlacklistedTypes()); + _output.WriteLine("Empty batch blacklist results in no changes"); + } + + [Fact] + public void BlacklistTypes_DuplicateTypes_AddsOnlyOnce() + { + // Arrange + var reflector = new Reflector(); + + // Act - Add same type multiple times + reflector.Converters.BlacklistTypes( + typeof(BlacklistedBaseClass), + typeof(BlacklistedBaseClass), + typeof(BlacklistedBaseClass)); + + // Assert + Assert.Single(reflector.Converters.GetAllBlacklistedTypes()); + Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(BlacklistedBaseClass))); + _output.WriteLine("Duplicate types in batch are correctly deduplicated"); + } + + [Fact] + public void BlacklistTypes_DerivedTypesInBatch_AllDetected() + { + // Arrange + var reflector = new Reflector(); + + // Act + reflector.Converters.BlacklistTypes(typeof(BlacklistedBaseClass)); + + // Assert - Derived types should also be blacklisted + Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(DerivedFromBlacklisted))); + Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(DeeplyDerivedFromBlacklisted))); + _output.WriteLine("Derived types are correctly blacklisted after batch operation"); + } + + #endregion + + #region String-Based Blacklist Method Tests + + [Fact] + public void BlacklistType_ByStringName_TypeIsBlacklisted() + { + // Arrange + var reflector = new Reflector(); + var typeFullName = typeof(BlacklistedBaseClass).FullName!; + + // Act + reflector.Converters.BlacklistType(typeFullName); + + // Assert + Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(BlacklistedBaseClass))); + _output.WriteLine($"Type blacklisted by string name '{typeFullName}' is correctly detected"); + } + + [Fact] + public void BlacklistType_ByStringName_SystemType_IsBlacklisted() + { + // Arrange + var reflector = new Reflector(); + + // Act + reflector.Converters.BlacklistType("System.String"); + + // Assert + Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(string))); + _output.WriteLine("System.String blacklisted by string name is correctly detected"); + } + + [Fact] + public void BlacklistType_ByStringName_InvalidTypeName_NoException() + { + // Arrange + var reflector = new Reflector(); + + // Act - Should not throw for invalid type name + reflector.Converters.BlacklistType("This.Type.Does.Not.Exist"); + + // Assert - No types should be blacklisted + Assert.Empty(reflector.Converters.GetAllBlacklistedTypes()); + _output.WriteLine("Invalid type name is silently ignored"); + } + + [Fact] + public void BlacklistTypes_ByStringNames_AllTypesAreBlacklisted() + { + // Arrange + var reflector = new Reflector(); + + // Act + reflector.Converters.BlacklistTypes( + "System.String", + "System.Int32", + "System.DateTime"); + + // Assert + Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(string))); + Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(int))); + Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(DateTime))); + _output.WriteLine("Multiple types blacklisted by string names are correctly detected"); + } + + [Fact] + public void BlacklistTypes_ByStringNames_MixedValidAndInvalid_OnlyValidAdded() + { + // Arrange + var reflector = new Reflector(); + + // Act - Mix of valid and invalid type names + reflector.Converters.BlacklistTypes( + "System.String", + "This.Does.Not.Exist", + "System.Int32"); + + // Assert + Assert.Equal(2, reflector.Converters.GetAllBlacklistedTypes().Count); + Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(string))); + Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(int))); + _output.WriteLine("Only valid type names from batch are blacklisted"); + } + + [Fact] + public void BlacklistTypes_ByStringNames_EmptyArray_NoChange() + { + // Arrange + var reflector = new Reflector(); + + // Act + reflector.Converters.BlacklistTypes(Array.Empty()); + + // Assert + Assert.Empty(reflector.Converters.GetAllBlacklistedTypes()); + _output.WriteLine("Empty string array batch results in no changes"); + } + + [Fact] + public void BlacklistTypes_ByStringNames_DuplicateNames_AddsOnlyOnce() + { + // Arrange + var reflector = new Reflector(); + + // Act + reflector.Converters.BlacklistTypes( + "System.String", + "System.String", + "System.String"); + + // Assert + Assert.Single(reflector.Converters.GetAllBlacklistedTypes()); + Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(string))); + _output.WriteLine("Duplicate string names in batch are correctly deduplicated"); + } + + [Fact] + public void BlacklistTypes_ByStringNames_GenericType_IsBlacklisted() + { + // Arrange + var reflector = new Reflector(); + var listStringTypeName = typeof(List).FullName!; + + // Act + reflector.Converters.BlacklistTypes(listStringTypeName); + + // Assert + Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(List))); + _output.WriteLine($"Generic type '{listStringTypeName}' blacklisted by string name is correctly detected"); + } + + [Fact] + public void BlacklistTypes_ByStringNames_CacheInvalidation_WorksCorrectly() + { + // Arrange + var reflector = new Reflector(); + + // Prime cache with false result + Assert.False(reflector.Converters.IsTypeBlacklisted(typeof(string))); + + // Act + reflector.Converters.BlacklistTypes("System.String"); + + // Assert - Cache should be invalidated + Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(string))); + _output.WriteLine("Cache is correctly invalidated after string-based batch blacklist"); + } + + #endregion + #region Concurrency and Cache Tests [Fact] diff --git a/ReflectorNet/src/Reflector/Reflector.Registry.cs b/ReflectorNet/src/Reflector/Reflector.Registry.cs index c0903cf..b2e9174 100644 --- a/ReflectorNet/src/Reflector/Reflector.Registry.cs +++ b/ReflectorNet/src/Reflector/Reflector.Registry.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using com.IvanMurzak.ReflectorNet.Converter; +using com.IvanMurzak.ReflectorNet.Utils; namespace com.IvanMurzak.ReflectorNet { @@ -117,6 +118,54 @@ public void BlacklistType(Type type) _blacklistCache = new ConcurrentDictionary(); // Invalidate cache when blacklist changes } + /// + /// Adds multiple types to the blacklist, preventing them from being processed by any converter. + /// The blacklist cache is only invalidated if at least one new type was added. + /// + /// The types to add to the blacklist. Null values are ignored. + public void BlacklistTypes(params Type[] types) + { + var changed = false; + foreach (var type in types) + { + if (type != null && _blacklistedTypes.TryAdd(type, 0)) + changed = true; + } + if (changed) + _blacklistCache = new ConcurrentDictionary(); // Invalidate cache when blacklist changes + } + + /// + /// Adds a type to the blacklist by its full name, preventing it from being processed by any converter. + /// The type is resolved using . + /// + /// The full name of the type to blacklist (e.g., "System.String"). + public void BlacklistType(string typeFullName) + { + var type = TypeUtils.GetType(typeFullName); + if (type != null) + BlacklistType(type); + } + + /// + /// Adds multiple types to the blacklist by their full names, preventing them from being processed by any converter. + /// Types are resolved using . The blacklist cache is only invalidated + /// if at least one new type was successfully resolved and added. + /// + /// The full names of the types to blacklist (e.g., "System.String", "System.Int32"). + public void BlacklistTypes(params string[] typeFullNames) + { + var changed = false; + foreach (var typeFullName in typeFullNames) + { + var type = TypeUtils.GetType(typeFullName); + if (type != null && _blacklistedTypes.TryAdd(type, 0)) + changed = true; + } + if (changed) + _blacklistCache = new ConcurrentDictionary(); // Invalidate cache when blacklist changes + } + /// /// Checks if a type is blacklisted. This includes: /// - The type itself being blacklisted From 6c053a0f2fb0e1aa86cf4d3cfaea26ddec58dbcf Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Sat, 10 Jan 2026 02:58:08 -0800 Subject: [PATCH 2/2] feat: Update blacklist methods to return boolean indicating success or failure --- .../ReflectorTests/IsTypeBlacklistedTests.cs | 123 +++++++++++++++--- ReflectorNet/ReflectorNet.csproj | 2 +- .../src/Reflector/Reflector.Registry.cs | 25 +++- 3 files changed, 126 insertions(+), 24 deletions(-) diff --git a/ReflectorNet.Tests/src/ReflectorTests/IsTypeBlacklistedTests.cs b/ReflectorNet.Tests/src/ReflectorTests/IsTypeBlacklistedTests.cs index 8d7cc3f..05bbd91 100644 --- a/ReflectorNet.Tests/src/ReflectorTests/IsTypeBlacklistedTests.cs +++ b/ReflectorNet.Tests/src/ReflectorTests/IsTypeBlacklistedTests.cs @@ -853,12 +853,13 @@ public void BlacklistTypes_MultipleTypes_AllAreBlacklisted() var reflector = new Reflector(); // Act - reflector.Converters.BlacklistTypes( + var result = reflector.Converters.BlacklistTypes( typeof(BlacklistedBaseClass), typeof(NonBlacklistedClass), typeof(IBlacklistedInterface)); // Assert + Assert.True(result, "BlacklistTypes should return true when types are added"); Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(BlacklistedBaseClass))); Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(NonBlacklistedClass))); Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(IBlacklistedInterface))); @@ -872,12 +873,13 @@ public void BlacklistTypes_WithNullValues_IgnoresNulls() var reflector = new Reflector(); // Act - Include null values which should be ignored - reflector.Converters.BlacklistTypes( + var result = reflector.Converters.BlacklistTypes( typeof(BlacklistedBaseClass), null!, typeof(NonBlacklistedClass)); // Assert + Assert.True(result, "BlacklistTypes should return true when at least one type is added"); Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(BlacklistedBaseClass))); Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(NonBlacklistedClass))); Assert.Equal(2, reflector.Converters.GetAllBlacklistedTypes().Count); @@ -891,9 +893,10 @@ public void BlacklistTypes_EmptyArray_NoChange() var reflector = new Reflector(); // Act - reflector.Converters.BlacklistTypes(Array.Empty()); + var result = reflector.Converters.BlacklistTypes(Array.Empty()); // Assert + Assert.False(result, "BlacklistTypes should return false when no types are added"); Assert.Empty(reflector.Converters.GetAllBlacklistedTypes()); _output.WriteLine("Empty batch blacklist results in no changes"); } @@ -905,12 +908,13 @@ public void BlacklistTypes_DuplicateTypes_AddsOnlyOnce() var reflector = new Reflector(); // Act - Add same type multiple times - reflector.Converters.BlacklistTypes( + var result = reflector.Converters.BlacklistTypes( typeof(BlacklistedBaseClass), typeof(BlacklistedBaseClass), typeof(BlacklistedBaseClass)); // Assert + Assert.True(result, "BlacklistTypes should return true when at least one type is added"); Assert.Single(reflector.Converters.GetAllBlacklistedTypes()); Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(BlacklistedBaseClass))); _output.WriteLine("Duplicate types in batch are correctly deduplicated"); @@ -923,14 +927,45 @@ public void BlacklistTypes_DerivedTypesInBatch_AllDetected() var reflector = new Reflector(); // Act - reflector.Converters.BlacklistTypes(typeof(BlacklistedBaseClass)); + var result = reflector.Converters.BlacklistTypes(typeof(BlacklistedBaseClass)); // Assert - Derived types should also be blacklisted + Assert.True(result, "BlacklistTypes should return true when type is added"); Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(DerivedFromBlacklisted))); Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(DeeplyDerivedFromBlacklisted))); _output.WriteLine("Derived types are correctly blacklisted after batch operation"); } + [Fact] + public void BlacklistTypes_AlreadyBlacklisted_ReturnsFalse() + { + // Arrange + var reflector = new Reflector(); + reflector.Converters.BlacklistTypes(typeof(BlacklistedBaseClass)); + + // Act - Try to add the same type again + var result = reflector.Converters.BlacklistTypes(typeof(BlacklistedBaseClass)); + + // Assert + Assert.False(result, "BlacklistTypes should return false when all types are already blacklisted"); + _output.WriteLine("BlacklistTypes returns false when type already blacklisted"); + } + + [Fact] + public void BlacklistTypes_OnlyNulls_ReturnsFalse() + { + // Arrange + var reflector = new Reflector(); + + // Act - Only null values + var result = reflector.Converters.BlacklistTypes((Type)null!, (Type)null!); + + // Assert + Assert.False(result, "BlacklistTypes should return false when only null values provided"); + Assert.Empty(reflector.Converters.GetAllBlacklistedTypes()); + _output.WriteLine("BlacklistTypes returns false when only nulls provided"); + } + #endregion #region String-Based Blacklist Method Tests @@ -943,9 +978,10 @@ public void BlacklistType_ByStringName_TypeIsBlacklisted() var typeFullName = typeof(BlacklistedBaseClass).FullName!; // Act - reflector.Converters.BlacklistType(typeFullName); + var result = reflector.Converters.BlacklistType(typeFullName); // Assert + Assert.True(result, "BlacklistType should return true when type is added"); Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(BlacklistedBaseClass))); _output.WriteLine($"Type blacklisted by string name '{typeFullName}' is correctly detected"); } @@ -957,25 +993,42 @@ public void BlacklistType_ByStringName_SystemType_IsBlacklisted() var reflector = new Reflector(); // Act - reflector.Converters.BlacklistType("System.String"); + var result = reflector.Converters.BlacklistType("System.String"); // Assert + Assert.True(result, "BlacklistType should return true when type is added"); Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(string))); _output.WriteLine("System.String blacklisted by string name is correctly detected"); } [Fact] - public void BlacklistType_ByStringName_InvalidTypeName_NoException() + public void BlacklistType_ByStringName_InvalidTypeName_ReturnsFalse() { // Arrange var reflector = new Reflector(); // Act - Should not throw for invalid type name - reflector.Converters.BlacklistType("This.Type.Does.Not.Exist"); + var result = reflector.Converters.BlacklistType("This.Type.Does.Not.Exist"); // Assert - No types should be blacklisted + Assert.False(result, "BlacklistType should return false for invalid type name"); Assert.Empty(reflector.Converters.GetAllBlacklistedTypes()); - _output.WriteLine("Invalid type name is silently ignored"); + _output.WriteLine("Invalid type name returns false and is silently ignored"); + } + + [Fact] + public void BlacklistType_ByStringName_AlreadyBlacklisted_ReturnsFalse() + { + // Arrange + var reflector = new Reflector(); + reflector.Converters.BlacklistType("System.String"); + + // Act - Try to add the same type again + var result = reflector.Converters.BlacklistType("System.String"); + + // Assert + Assert.False(result, "BlacklistType should return false when type already blacklisted"); + _output.WriteLine("BlacklistType returns false when type already blacklisted"); } [Fact] @@ -985,12 +1038,13 @@ public void BlacklistTypes_ByStringNames_AllTypesAreBlacklisted() var reflector = new Reflector(); // Act - reflector.Converters.BlacklistTypes( + var result = reflector.Converters.BlacklistTypes( "System.String", "System.Int32", "System.DateTime"); // Assert + Assert.True(result, "BlacklistTypes should return true when types are added"); Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(string))); Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(int))); Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(DateTime))); @@ -1004,12 +1058,13 @@ public void BlacklistTypes_ByStringNames_MixedValidAndInvalid_OnlyValidAdded() var reflector = new Reflector(); // Act - Mix of valid and invalid type names - reflector.Converters.BlacklistTypes( + var result = reflector.Converters.BlacklistTypes( "System.String", "This.Does.Not.Exist", "System.Int32"); // Assert + Assert.True(result, "BlacklistTypes should return true when at least one type is added"); Assert.Equal(2, reflector.Converters.GetAllBlacklistedTypes().Count); Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(string))); Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(int))); @@ -1023,9 +1078,10 @@ public void BlacklistTypes_ByStringNames_EmptyArray_NoChange() var reflector = new Reflector(); // Act - reflector.Converters.BlacklistTypes(Array.Empty()); + var result = reflector.Converters.BlacklistTypes(Array.Empty()); // Assert + Assert.False(result, "BlacklistTypes should return false when no types are added"); Assert.Empty(reflector.Converters.GetAllBlacklistedTypes()); _output.WriteLine("Empty string array batch results in no changes"); } @@ -1037,12 +1093,13 @@ public void BlacklistTypes_ByStringNames_DuplicateNames_AddsOnlyOnce() var reflector = new Reflector(); // Act - reflector.Converters.BlacklistTypes( + var result = reflector.Converters.BlacklistTypes( "System.String", "System.String", "System.String"); // Assert + Assert.True(result, "BlacklistTypes should return true when at least one type is added"); Assert.Single(reflector.Converters.GetAllBlacklistedTypes()); Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(string))); _output.WriteLine("Duplicate string names in batch are correctly deduplicated"); @@ -1056,9 +1113,10 @@ public void BlacklistTypes_ByStringNames_GenericType_IsBlacklisted() var listStringTypeName = typeof(List).FullName!; // Act - reflector.Converters.BlacklistTypes(listStringTypeName); + var result = reflector.Converters.BlacklistTypes(listStringTypeName); // Assert + Assert.True(result, "BlacklistTypes should return true when type is added"); Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(List))); _output.WriteLine($"Generic type '{listStringTypeName}' blacklisted by string name is correctly detected"); } @@ -1073,13 +1131,46 @@ public void BlacklistTypes_ByStringNames_CacheInvalidation_WorksCorrectly() Assert.False(reflector.Converters.IsTypeBlacklisted(typeof(string))); // Act - reflector.Converters.BlacklistTypes("System.String"); + var result = reflector.Converters.BlacklistTypes("System.String"); // Assert - Cache should be invalidated + Assert.True(result, "BlacklistTypes should return true when type is added"); Assert.True(reflector.Converters.IsTypeBlacklisted(typeof(string))); _output.WriteLine("Cache is correctly invalidated after string-based batch blacklist"); } + [Fact] + public void BlacklistTypes_ByStringNames_AllInvalid_ReturnsFalse() + { + // Arrange + var reflector = new Reflector(); + + // Act - All invalid type names + var result = reflector.Converters.BlacklistTypes( + "This.Does.Not.Exist", + "Neither.Does.This"); + + // Assert + Assert.False(result, "BlacklistTypes should return false when no types could be resolved"); + Assert.Empty(reflector.Converters.GetAllBlacklistedTypes()); + _output.WriteLine("BlacklistTypes returns false when all type names are invalid"); + } + + [Fact] + public void BlacklistTypes_ByStringNames_AlreadyBlacklisted_ReturnsFalse() + { + // Arrange + var reflector = new Reflector(); + reflector.Converters.BlacklistTypes("System.String", "System.Int32"); + + // Act - Try to add the same types again + var result = reflector.Converters.BlacklistTypes("System.String", "System.Int32"); + + // Assert + Assert.False(result, "BlacklistTypes should return false when all types already blacklisted"); + _output.WriteLine("BlacklistTypes returns false when all types already blacklisted"); + } + #endregion #region Concurrency and Cache Tests diff --git a/ReflectorNet/ReflectorNet.csproj b/ReflectorNet/ReflectorNet.csproj index f888fc4..155d801 100644 --- a/ReflectorNet/ReflectorNet.csproj +++ b/ReflectorNet/ReflectorNet.csproj @@ -9,7 +9,7 @@ com.IvanMurzak.ReflectorNet - 3.5.0 + 3.6.0 Ivan Murzak Copyright © Ivan Murzak 2025 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. diff --git a/ReflectorNet/src/Reflector/Reflector.Registry.cs b/ReflectorNet/src/Reflector/Reflector.Registry.cs index b2e9174..ad008c3 100644 --- a/ReflectorNet/src/Reflector/Reflector.Registry.cs +++ b/ReflectorNet/src/Reflector/Reflector.Registry.cs @@ -108,14 +108,19 @@ public void Remove() where T : IReflectionConverter /// /// Adds a type to the blacklist, preventing it from being processed by any converter. /// - /// - public void BlacklistType(Type type) + /// The type to add to the blacklist. + /// True if the type was added; false if it was null or already blacklisted. + public bool BlacklistType(Type type) { if (type == null) - return; + return false; if (_blacklistedTypes.TryAdd(type, 0)) + { _blacklistCache = new ConcurrentDictionary(); // Invalidate cache when blacklist changes + return true; + } + return false; } /// @@ -123,7 +128,8 @@ public void BlacklistType(Type type) /// The blacklist cache is only invalidated if at least one new type was added. /// /// The types to add to the blacklist. Null values are ignored. - public void BlacklistTypes(params Type[] types) + /// True if at least one type was added; false if all types were null or already blacklisted. + public bool BlacklistTypes(params Type[] types) { var changed = false; foreach (var type in types) @@ -133,6 +139,7 @@ public void BlacklistTypes(params Type[] types) } if (changed) _blacklistCache = new ConcurrentDictionary(); // Invalidate cache when blacklist changes + return changed; } /// @@ -140,11 +147,13 @@ public void BlacklistTypes(params Type[] types) /// The type is resolved using . /// /// The full name of the type to blacklist (e.g., "System.String"). - public void BlacklistType(string typeFullName) + /// True if the type was resolved and added; false if the type could not be resolved or was already blacklisted. + public bool BlacklistType(string typeFullName) { var type = TypeUtils.GetType(typeFullName); if (type != null) - BlacklistType(type); + return BlacklistType(type); + return false; } /// @@ -153,7 +162,8 @@ public void BlacklistType(string typeFullName) /// if at least one new type was successfully resolved and added. /// /// The full names of the types to blacklist (e.g., "System.String", "System.Int32"). - public void BlacklistTypes(params string[] typeFullNames) + /// True if at least one type was resolved and added; false if all types could not be resolved or were already blacklisted. + public bool BlacklistTypes(params string[] typeFullNames) { var changed = false; foreach (var typeFullName in typeFullNames) @@ -164,6 +174,7 @@ public void BlacklistTypes(params string[] typeFullNames) } if (changed) _blacklistCache = new ConcurrentDictionary(); // Invalidate cache when blacklist changes + return changed; } ///