diff --git a/docs/core/compatibility/10.0.md b/docs/core/compatibility/10.0.md index 7d0c66625293f..cff0a64fa8d8e 100644 --- a/docs/core/compatibility/10.0.md +++ b/docs/core/compatibility/10.0.md @@ -100,6 +100,12 @@ If you're migrating an app to .NET 10, the breaking changes listed here might af | [Streaming HTTP responses enabled by default in browser HTTP clients](networking/10.0/default-http-streaming.md) | Behavioral change | Preview 3 | | [`Uri` length limits removed](networking/10.0/uri-length-limits-removed.md) | Behavioral change | Preview 7 | +## Reflection + +| Title | Type of change | Introduced version | +|-------|-------------------|--------------------| +| [Replace DAMT.All with more restricted annotation on InvokeMember/FindMembers/DeclaredMembers](reflection/10.0/ireflect-damt-annotations.md) | Behavioral/source incompatible | Preview 1 | + ## SDK and MSBuild | Title | Type of change | Introduced version | diff --git a/docs/core/compatibility/reflection/10.0/ireflect-damt-annotations.md b/docs/core/compatibility/reflection/10.0/ireflect-damt-annotations.md new file mode 100644 index 0000000000000..ec44393ab811c --- /dev/null +++ b/docs/core/compatibility/reflection/10.0/ireflect-damt-annotations.md @@ -0,0 +1,51 @@ +--- +title: "Breaking change: Replace DAMT.All with more restricted annotation on InvokeMember/FindMembers/DeclaredMembers" +description: "Learn about the breaking change in .NET 10 where System.Reflection APIs InvokeMember, FindMembers, and DeclaredMembers use more restricted annotations instead of DAMT.All." +ms.date: 01/10/2025 +ai-usage: ai-generated +--- + +# Replace DAMT.All with more restricted annotation on InvokeMember/FindMembers/DeclaredMembers + +Starting in .NET 10, the APIs , , and have been updated to use more restricted annotations instead of . This change affects scenarios where developers implement the interface or derive from . The previous use of `DAMT.All` was overly permissive and could lead to unintended behavior, such as capturing interface methods implemented by a class or generating warnings due to unsafe reflection calls. + +## Version introduced + +.NET 10 Preview 1 + +## Previous behavior + +The , , and APIs used the annotation, which was overly permissive. This could result in capturing additional members, such as interface methods implemented by a class, and potentially cause runtime warnings or unsafe reflection calls. + +## New behavior + +The , , and APIs now use more restricted annotations, which provide better control over the members captured during reflection. Developers implementing or deriving from must update their annotations to match the new behavior. + +The following code snippet shows an example of the required annotation for implementing : + +:::code language="csharp" source="./snippets/ireflect-damt-annotations/csharp/MyType.cs" id="snippet_InvokeMember"::: + +:::code language="vb" source="./snippets/ireflect-damt-annotations/vb/MyType.vb" id="snippet_InvokeMember"::: + +## Type of breaking change + +This change is a [behavioral change](../../categories.md#behavioral-change) and can affect [source compatibility](../../categories.md#source-compatibility). + +## Reason for change + +The change was introduced to improve the accuracy of annotations in APIs and to address issues caused by the overly permissive annotation. This ensures better compatibility with trimming and reflection scenarios, reduces runtime warnings, and prevents unsafe reflection calls. + +## Recommended action + +Developers who implement or derive from should review their code and update annotations to align with the new behavior. Specifically: + +1. Replace annotations with more restricted annotations, such as , , or other appropriate types. +2. Test reflection scenarios to ensure that the updated annotations capture the intended members and don't introduce runtime errors or warnings. + +For more information on `DynamicallyAccessedMembers` annotations and their usage, refer to [Prepare .NET libraries for trimming](/dotnet/core/deploying/trimming/prepare-libraries-for-trimming). + +## Affected APIs + +- +- +- diff --git a/docs/core/compatibility/reflection/10.0/snippets/ireflect-damt-annotations/csharp/MyType.cs b/docs/core/compatibility/reflection/10.0/snippets/ireflect-damt-annotations/csharp/MyType.cs new file mode 100644 index 0000000000000..8fdde25f47faa --- /dev/null +++ b/docs/core/compatibility/reflection/10.0/snippets/ireflect-damt-annotations/csharp/MyType.cs @@ -0,0 +1,86 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Reflection; + +// +class MyType : IReflect +{ + [DynamicallyAccessedMembers( + DynamicallyAccessedMemberTypes.PublicFields | + DynamicallyAccessedMemberTypes.NonPublicFields | + DynamicallyAccessedMemberTypes.PublicMethods | + DynamicallyAccessedMemberTypes.NonPublicMethods | + DynamicallyAccessedMemberTypes.PublicProperties | + DynamicallyAccessedMemberTypes.NonPublicProperties | + DynamicallyAccessedMemberTypes.PublicConstructors | + DynamicallyAccessedMemberTypes.NonPublicConstructors)] + public object InvokeMember( + string name, + BindingFlags invokeAttr, + Binder? binder, + object? target, + object?[]? args, + ParameterModifier[]? modifiers, + CultureInfo? culture, + string[]? namedParameters) + { + throw new NotImplementedException(); + } + + public FieldInfo? GetField(string name, BindingFlags bindingAttr) + { + throw new NotImplementedException(); + } + + public FieldInfo[] GetFields(BindingFlags bindingAttr) + { + throw new NotImplementedException(); + } + + public MemberInfo[] GetMember(string name, BindingFlags bindingAttr) + { + throw new NotImplementedException(); + } + + public MemberInfo[] GetMembers(BindingFlags bindingAttr) + { + throw new NotImplementedException(); + } + + public MethodInfo? GetMethod(string name, BindingFlags bindingAttr) + { + throw new NotImplementedException(); + } + + public MethodInfo? GetMethod(string name, BindingFlags bindingAttr, Binder? binder, Type[] types, ParameterModifier[]? modifiers) + { + throw new NotImplementedException(); + } + + public MethodInfo[] GetMethods(BindingFlags bindingAttr) + { + throw new NotImplementedException(); + } + + public PropertyInfo[] GetProperties(BindingFlags bindingAttr) + { + throw new NotImplementedException(); + } + + public PropertyInfo? GetProperty(string name, BindingFlags bindingAttr) + { + throw new NotImplementedException(); + } + + public PropertyInfo? GetProperty(string name, BindingFlags bindingAttr, Binder? binder, Type? returnType, Type[] types, ParameterModifier[]? modifiers) + { + throw new NotImplementedException(); + } + + public Type UnderlyingSystemType + { + get { throw new NotImplementedException(); } + } +} +// diff --git a/docs/core/compatibility/reflection/10.0/snippets/ireflect-damt-annotations/csharp/ireflect-damt-annotations-csharp.csproj b/docs/core/compatibility/reflection/10.0/snippets/ireflect-damt-annotations/csharp/ireflect-damt-annotations-csharp.csproj new file mode 100644 index 0000000000000..0b5411c0c8457 --- /dev/null +++ b/docs/core/compatibility/reflection/10.0/snippets/ireflect-damt-annotations/csharp/ireflect-damt-annotations-csharp.csproj @@ -0,0 +1,9 @@ + + + + Library + net9.0 + enable + + + diff --git a/docs/core/compatibility/reflection/10.0/snippets/ireflect-damt-annotations/vb/MyType.vb b/docs/core/compatibility/reflection/10.0/snippets/ireflect-damt-annotations/vb/MyType.vb new file mode 100644 index 0000000000000..200a34e862039 --- /dev/null +++ b/docs/core/compatibility/reflection/10.0/snippets/ireflect-damt-annotations/vb/MyType.vb @@ -0,0 +1,77 @@ +Imports System +Imports System.Diagnostics.CodeAnalysis +Imports System.Globalization +Imports System.Reflection + +' +Class MyType + Implements IReflect + + + Public Function InvokeMember( + name As String, + invokeAttr As BindingFlags, + binder As Binder, + target As Object, + args As Object(), + modifiers As ParameterModifier(), + culture As CultureInfo, + namedParameters As String()) As Object Implements IReflect.InvokeMember + Throw New NotImplementedException() + End Function + + Public Function GetField(name As String, bindingAttr As BindingFlags) As FieldInfo Implements IReflect.GetField + Throw New NotImplementedException() + End Function + + Public Function GetFields(bindingAttr As BindingFlags) As FieldInfo() Implements IReflect.GetFields + Throw New NotImplementedException() + End Function + + Public Function GetMember(name As String, bindingAttr As BindingFlags) As MemberInfo() Implements IReflect.GetMember + Throw New NotImplementedException() + End Function + + Public Function GetMembers(bindingAttr As BindingFlags) As MemberInfo() Implements IReflect.GetMembers + Throw New NotImplementedException() + End Function + + Public Function GetMethod(name As String, bindingAttr As BindingFlags) As MethodInfo Implements IReflect.GetMethod + Throw New NotImplementedException() + End Function + + Public Function GetMethod(name As String, bindingAttr As BindingFlags, binder As Binder, types As Type(), modifiers As ParameterModifier()) As MethodInfo Implements IReflect.GetMethod + Throw New NotImplementedException() + End Function + + Public Function GetMethods(bindingAttr As BindingFlags) As MethodInfo() Implements IReflect.GetMethods + Throw New NotImplementedException() + End Function + + Public Function GetProperties(bindingAttr As BindingFlags) As PropertyInfo() Implements IReflect.GetProperties + Throw New NotImplementedException() + End Function + + Public Function GetProperty(name As String, bindingAttr As BindingFlags) As PropertyInfo Implements IReflect.GetProperty + Throw New NotImplementedException() + End Function + + Public Function GetProperty(name As String, bindingAttr As BindingFlags, binder As Binder, returnType As Type, types As Type(), modifiers As ParameterModifier()) As PropertyInfo Implements IReflect.GetProperty + Throw New NotImplementedException() + End Function + + Public ReadOnly Property UnderlyingSystemType As Type Implements IReflect.UnderlyingSystemType + Get + Throw New NotImplementedException() + End Get + End Property +End Class +' diff --git a/docs/core/compatibility/reflection/10.0/snippets/ireflect-damt-annotations/vb/ireflect-damt-annotations-vb.vbproj b/docs/core/compatibility/reflection/10.0/snippets/ireflect-damt-annotations/vb/ireflect-damt-annotations-vb.vbproj new file mode 100644 index 0000000000000..e44896b7a4f58 --- /dev/null +++ b/docs/core/compatibility/reflection/10.0/snippets/ireflect-damt-annotations/vb/ireflect-damt-annotations-vb.vbproj @@ -0,0 +1,9 @@ + + + + Library + net9.0 + IReflectDamtAnnotations + + + diff --git a/docs/core/compatibility/toc.yml b/docs/core/compatibility/toc.yml index 18c08be85a233..5c80b7eb4346f 100644 --- a/docs/core/compatibility/toc.yml +++ b/docs/core/compatibility/toc.yml @@ -110,6 +110,10 @@ items: href: networking/10.0/default-http-streaming.md - name: "'Uri' length limits removed" href: networking/10.0/uri-length-limits-removed.md + - name: Reflection + items: + - name: Replace DAMT.All with more restricted annotation on InvokeMember/FindMembers/DeclaredMembers + href: reflection/10.0/ireflect-damt-annotations.md - name: SDK and MSBuild items: - name: .NET CLI `--interactive` defaults to `true` in user scenarios