diff --git a/docs/fundamentals/runtime-libraries/snippets/system-reflection-context-customreflectioncontext/csharp/CustomReflectionContextExample.csproj b/docs/fundamentals/runtime-libraries/snippets/system-reflection-context-customreflectioncontext/csharp/CustomReflectionContextExample.csproj new file mode 100644 index 0000000000000..c1471653bed76 --- /dev/null +++ b/docs/fundamentals/runtime-libraries/snippets/system-reflection-context-customreflectioncontext/csharp/CustomReflectionContextExample.csproj @@ -0,0 +1,12 @@ + + + + Exe + net10.0 + + + + + + + diff --git a/docs/fundamentals/runtime-libraries/snippets/system-reflection-context-customreflectioncontext/csharp/program.cs b/docs/fundamentals/runtime-libraries/snippets/system-reflection-context-customreflectioncontext/csharp/program.cs new file mode 100644 index 0000000000000..4527a78c7d647 --- /dev/null +++ b/docs/fundamentals/runtime-libraries/snippets/system-reflection-context-customreflectioncontext/csharp/program.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Context; + +namespace ConsoleApplication1 +{ + // + //A blank example attribute. + class MyAttribute : Attribute + { + } + + //Reflection context with custom rules. + class MyCustomReflectionContext : CustomReflectionContext + { + //Called whenever the reflection context checks for custom attributes. + protected override IEnumerable GetCustomAttributes(MemberInfo member, IEnumerable declaredAttributes) + { + //Add example attribute to "To*" members. + if (member.Name.StartsWith("To")) + { + yield return new MyAttribute(); + } + //Keep existing attributes as well. + foreach (var attr in declaredAttributes) yield return attr; + } + } + + class Program + { + static void Main(string[] args) + { + MyCustomReflectionContext mc = new MyCustomReflectionContext(); + Type t = typeof(String); + + //A representation of the type in the default reflection context. + TypeInfo ti = t.GetTypeInfo(); + + //A representation of the type in the customized reflection context. + TypeInfo myTI = mc.MapType(ti); + + //Display all the members of the type and their attributes. + foreach (MemberInfo m in myTI.DeclaredMembers) + { + Console.WriteLine(m.Name + ":"); + foreach (Attribute cd in m.GetCustomAttributes()) + { + Console.WriteLine(cd.GetType()); + } + } + + Console.WriteLine(); + + //The "ToString" member as represented in the default reflection context. + MemberInfo mi1 = ti.GetDeclaredMethods("ToString").FirstOrDefault(); + + //All the attributes of "ToString" in the default reflection context. + Console.WriteLine("'ToString' Attributes in Default Reflection Context:"); + foreach (Attribute cd in mi1.GetCustomAttributes()) + { + Console.WriteLine(cd.GetType()); + } + + Console.WriteLine(); + + //The same member in the custom reflection context. + mi1 = myTI.GetDeclaredMethods("ToString").FirstOrDefault(); + + //All its attributes, for comparison. MyAttribute is now included. + Console.WriteLine("'ToString' Attributes in Custom Reflection Context:"); + foreach (Attribute cd in mi1.GetCustomAttributes()) + { + Console.WriteLine(cd.GetType()); + } + + Console.ReadLine(); + } + } + // +} diff --git a/docs/fundamentals/runtime-libraries/system-reflection-context-customreflectioncontext.md b/docs/fundamentals/runtime-libraries/system-reflection-context-customreflectioncontext.md new file mode 100644 index 0000000000000..4a0c4689f0480 --- /dev/null +++ b/docs/fundamentals/runtime-libraries/system-reflection-context-customreflectioncontext.md @@ -0,0 +1,33 @@ +--- +title: System.Reflection.Context.CustomReflectionContext class +description: Learn about the System.Reflection.Context.CustomReflectionContext class. +ms.date: 02/12/2026 +ai-usage: ai-assisted +--- +# System.Reflection.Context.CustomReflectionContext class + +[!INCLUDE [context](includes/context.md)] + + provides a way for you to add or remove custom attributes from reflection objects, or add dummy properties to those objects, without re-implementing the complete reflection model. The default simply wraps reflection objects without making any changes, but by subclassing and overriding the relevant methods, you can add, remove, or change the attributes that apply to any reflected parameter or member, or add new properties to a reflected type. + +For example, suppose that your code follows the convention of applying a particular attribute to factory methods, but you're now required to work with third-party code that lacks attributes. You can use to specify a rule for identifying the objects that should have attributes and to supply the objects with those attributes when they're viewed from your code. + +To use effectively, the code that uses the reflected objects must support the notion of specifying a reflection context, instead of assuming that all reflected objects are associated with the runtime reflection context. Many reflection methods in the .NET Framework provide a parameter for this purpose. + +To modify the attributes that are applied to a reflected parameter or member, override the or method. These methods take the reflected object and the list of attributes under its current reflection context, and return the list of attributes it should have under the custom reflection context. + +> [!WARNING] +> methods should not access the list of attributes of a reflected object or method directly by calling the method on the provided or instance, but should instead use the `declaredAttributes` list, which is passed as a parameter to the method overloads. + +To add properties to a reflected type, override the method. The method accepts a parameter that specifies the reflected type, and returns a list of additional properties. You should use the method to create property objects to return. You can specify delegates when creating the property that serve as the property accessor, and you can omit one of the accessors to create a read-only or write-only property. Note that such dummy properties have no metadata or Common Intermediate Language (CIL) backing. + +> [!WARNING] +> +> - Be cautious about equality among reflected objects when you work with reflection contexts, because objects might represent the same reflected object in multiple contexts. You can use the method to obtain a particular reflection context's version of a reflected object. +> - A object alters the attributes returned by a particular reflection object, such as those obtained by the method. It doesn't alter the custom attribute data returned by the method, and these two lists won't match when you use a custom reflection context. + +## Example + +The following example demonstrates how to subclass to add a custom attribute to all the members of a given type whose names begin with "To". To run this code, paste it into an empty console project and add a reference to the `System.Reflection.Context` NuGet package. + +:::code language="csharp" source="./snippets/system-reflection-context-customreflectioncontext/csharp/program.cs" id="Snippet1"::: diff --git a/docs/fundamentals/toc.yml b/docs/fundamentals/toc.yml index b59d223cc2de6..c6b1727205d44 100644 --- a/docs/fundamentals/toc.yml +++ b/docs/fundamentals/toc.yml @@ -1394,6 +1394,8 @@ items: href: runtime-libraries/system-type-gettype.md - name: MakeGenericType method href: runtime-libraries/system-type-makegenerictype.md + - name: The CustomReflectionContext class + href: runtime-libraries/system-reflection-context-customreflectioncontext.md - name: Graphics items: - name: Supplemental API remarks