Skip to content

Commit

Permalink
Add metadata update handler to System.ComponentModel.TypeConverter (#…
Browse files Browse the repository at this point in the history
…51466)

* Add metadata update handler to System.ComponentModel.TypeConverter

* Update src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/ReflectTypeDescriptionProvider.cs
  • Loading branch information
stephentoub authored Apr 20, 2021
1 parent 53e713f commit 291e7c0
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
<Compile Include="System\ComponentModel\MemberDescriptor.cs" />
<Compile Include="System\ComponentModel\PropertyDescriptorCollection.cs" />
<Compile Include="System\ComponentModel\ProvidePropertyAttribute.cs" />
<Compile Include="System\ComponentModel\ReflectionCachesUpdateHandler.cs" />
<Compile Include="System\ComponentModel\ReflectEventDescriptor.cs" />
<Compile Include="System\ComponentModel\ReflectPropertyDescriptor.cs" />
<Compile Include="System\ComponentModel\ReflectTypeDescriptionProvider.cs" />
Expand Down Expand Up @@ -253,6 +254,7 @@
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.Extensions" />
<Reference Include="System.Runtime.InteropServices" />
<Reference Include="System.Runtime.Loader" />
<Reference Include="System.Runtime.Serialization.Formatters" />
<Reference Include="System.Text.RegularExpressions" />
<Reference Include="System.Threading" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,15 @@ private static EnumConverter CreateEnumConverter(Type type)

private static Hashtable ExtendedPropertyCache => LazyInitializer.EnsureInitialized(ref s_extendedPropertyCache, () => new Hashtable());

/// <summary>Clear the global caches this maintains on top of reflection.</summary>
internal static void ClearReflectionCaches()
{
s_propertyCache = null;
s_eventCache = null;
s_attributeCache = null;
s_extendedPropertyCache = null;
}

/// <summary>
/// Adds an editor table for the given editor base type.
/// Typically, editors are specified as metadata on an object. If no metadata for a
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable enable
using System.ComponentModel;
using System.Reflection;
using System.Reflection.Metadata;

[assembly: MetadataUpdateHandler(typeof(ReflectionCachesUpdateHandler))]

namespace System.ComponentModel
{
internal static class ReflectionCachesUpdateHandler
{
public static void BeforeUpdate(Type[]? types)
{
// ReflectTypeDescriptionProvider maintains global caches on top of reflection.
// Clear those.
ReflectTypeDescriptionProvider.ClearReflectionCaches();

// Each type descriptor may also cache reflection-based state that it gathered
// from ReflectTypeDescriptionProvider. Clear those as well.
if (types is not null)
{
foreach (Type type in types)
{
TypeDescriptor.Refresh(type);
}
}
else
{
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
TypeDescriptor.Refresh(assembly);
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Reflection;
using Xunit;

namespace System.ComponentModel.Tests
{
[SimpleUpdateTest]
public class ReflectionCachesUpdateHandlerTests
{
[Fact]
public void ReflectionCachesUpdateHandler_CachesCleared()
{
AttributeCollection ac1 = TypeDescriptor.GetAttributes(typeof(ReflectionCachesUpdateHandlerTests));
AttributeCollection ac2 = TypeDescriptor.GetAttributes(typeof(ReflectionCachesUpdateHandlerTests));
Assert.Equal(ac1.Count, ac2.Count);
Assert.Equal(1, ac1.Count);
Assert.Same(ac1[0], ac2[0]);

MethodInfo beforeUpdate = typeof(TypeDescriptionProvider).Assembly.GetType("System.ComponentModel.ReflectionCachesUpdateHandler", throwOnError: true).GetMethod("BeforeUpdate");
Assert.NotNull(beforeUpdate);
beforeUpdate.Invoke(null, new object[] { null });

AttributeCollection ac3 = TypeDescriptor.GetAttributes(typeof(ReflectionCachesUpdateHandlerTests));
Assert.NotSame(ac1[0], ac3[0]);
}
}

[AttributeUsage(AttributeTargets.All)]
internal sealed class SimpleUpdateTestAttribute : Attribute { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
<Compile Include="Mocks\MockServiceProvider.cs" />
<Compile Include="MultilineStringConverterTests.cs" />
<Compile Include="NullableConverterTests.cs" />
<Compile Include="ReflectionCachesUpdateHandlerTests.cs" />
<Compile Include="PropertyDescriptorCollectionTests.cs" />
<Compile Include="PropertyDescriptorTests.cs" />
<Compile Include="ProvidePropertyAttributeTests.cs" />
Expand Down

0 comments on commit 291e7c0

Please sign in to comment.