|
31 | 31 | <Docs>
|
32 | 32 | <summary>Provides access to an inaccessible member of a specific type.</summary>
|
33 | 33 | <remarks>
|
34 |
| - <format type="text/markdown"><![CDATA[ |
35 |
| -
|
36 |
| -## Remarks |
37 |
| -
|
38 |
| -You can apply this attribute to an `extern static` method. The implementation of the `extern static` method annotated with this attribute will be provided by the runtime based on the information in the attribute and the signature of the method that the attribute is applied to. The runtime will try to find the matching method or field and forward the call to it. If the matching method or field is not found, the body of the `extern static` method will throw <xref:System.MissingFieldException> or <xref:System.MissingMethodException>. |
39 |
| -
|
40 |
| -For <xref:System.Runtime.CompilerServices.UnsafeAccessorKind.Method>, <xref:System.Runtime.CompilerServices.UnsafeAccessorKind.StaticMethod>, <xref:System.Runtime.CompilerServices.UnsafeAccessorKind.Field>, and <xref:System.Runtime.CompilerServices.UnsafeAccessorKind.StaticField>, the type of the first argument of the annotated `extern static` method identifies the owning type. Only the specific type defined will be examined for inaccessible members. The type hierarchy is not walked looking for a match. |
41 |
| -
|
42 |
| -The value of the first argument is treated as `this` pointer for instance fields and methods. |
43 |
| -
|
44 |
| -The first argument must be passed as `ref` for instance fields and methods on structs. |
45 |
| -
|
46 |
| -The value of the first argument is not used by the implementation for `static` fields and methods. |
47 |
| -
|
48 |
| -The return value for an accessor to a field can be `ref` if setting of the field is desired. |
49 |
| -
|
50 |
| -
|
51 |
| -Constructors can be accessed using <xref:System.Runtime.CompilerServices.UnsafeAccessorKind.Constructor> or <xref:System.Runtime.CompilerServices.UnsafeAccessorKind.Method>. |
52 |
| -
|
53 |
| -
|
54 |
| -The return type is considered for the signature match. Modreqs and modopts are initially not considered for the signature match. However, if an ambiguity exists ignoring modreqs and modopts, a precise match is attempted. If an ambiguity still exists, <xref:System.Reflection.AmbiguousMatchException> is thrown. |
55 |
| -
|
56 |
| -By default, the attributed method's name dictates the name of the method/field. This can cause confusion in some cases since language abstractions, like C# local functions, generate mangled IL names. The solution to this is to use the `nameof` mechanism and define the <xref:System.Runtime.CompilerServices.UnsafeAccessorAttribute.Name> property. |
57 |
| -
|
| 34 | + <format type="text/markdown"><![CDATA[ |
| 35 | +
|
| 36 | +## Remarks |
| 37 | +
|
| 38 | +You can apply this attribute to an `extern static` method. The implementation of the `extern static` method annotated with this attribute will be provided by the runtime based on the information in the attribute and the signature of the method that the attribute is applied to. The runtime will try to find the matching method or field and forward the call to it. If the matching method or field is not found, the body of the `extern static` method will throw <xref:System.MissingFieldException> or <xref:System.MissingMethodException>. |
| 39 | +
|
| 40 | +Generic parameters are supported since .NET 9. Generic parameters must match the target in form and index (that is, type parameters must be type parameters and method parameters must be method parameters). The `extern static` method's generic parameters must also exactly match any constraints reflected on the target. If constraints don't match, the method throws <xref:System.InvalidProgramException>. |
| 41 | +
|
| 42 | +For <xref:System.Runtime.CompilerServices.UnsafeAccessorKind.Method>, <xref:System.Runtime.CompilerServices.UnsafeAccessorKind.StaticMethod>, <xref:System.Runtime.CompilerServices.UnsafeAccessorKind.Field>, and <xref:System.Runtime.CompilerServices.UnsafeAccessorKind.StaticField>, the type of the first argument of the annotated `extern static` method identifies the owning type. Only the specific type defined will be examined for inaccessible members. The type hierarchy is not walked looking for a match. |
| 43 | +
|
| 44 | +The value of the first argument is treated as `this` pointer for instance fields and methods. |
| 45 | +
|
| 46 | +The first argument must be passed as `ref` for instance fields and methods on structs. |
| 47 | +
|
| 48 | +The value of the first argument is not used by the implementation for `static` fields and methods and can be `null`. |
| 49 | +
|
| 50 | +The return value for an accessor to a field can be `ref` if setting of the field is desired. |
| 51 | +
|
| 52 | +
|
| 53 | +Constructors can be accessed using <xref:System.Runtime.CompilerServices.UnsafeAccessorKind.Constructor> or <xref:System.Runtime.CompilerServices.UnsafeAccessorKind.Method>. |
| 54 | +
|
| 55 | +
|
| 56 | +The return type is considered for the signature match. Modreqs and modopts are initially not considered for the signature match. However, if an ambiguity exists ignoring modreqs and modopts, a precise match is attempted. If an ambiguity still exists, <xref:System.Reflection.AmbiguousMatchException> is thrown. |
| 57 | +
|
| 58 | +By default, the attributed method's name dictates the name of the method/field. This can cause confusion in some cases since language abstractions, like C# local functions, generate mangled IL names. The solution to this is to use the `nameof` mechanism and define the <xref:System.Runtime.CompilerServices.UnsafeAccessorAttribute.Name> property. |
| 59 | +
|
58 | 60 | ]]></format>
|
59 | 61 | </remarks>
|
60 | 62 | <example>
|
61 |
| - <code language="csharp"> |
62 |
| - public class Class |
63 |
| - { |
64 |
| - static void StaticPrivateMethod() { } |
65 |
| - static int StaticPrivateField; |
66 |
| - Class(int i) { PrivateField = i; } |
67 |
| - void PrivateMethod() { } |
68 |
| - int PrivateField; |
69 |
| - int PrivateProperty { get => PrivateField; } |
70 |
| - } |
71 |
| - |
72 |
| - public void CallStaticPrivateMethod() |
73 |
| - { |
74 |
| - StaticPrivateMethod(null); |
75 |
| - |
76 |
| - [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = nameof(StaticPrivateMethod))] |
77 |
| - extern static void StaticPrivateMethod(Class c); |
78 |
| - } |
79 |
| - public void GetSetStaticPrivateField() |
80 |
| - { |
81 |
| - ref int f = ref GetSetStaticPrivateField(null); |
82 |
| - |
83 |
| - [UnsafeAccessor(UnsafeAccessorKind.StaticField, Name = "StaticPrivateField")] |
84 |
| - extern static ref int GetSetStaticPrivateField(Class c); |
85 |
| - } |
86 |
| - public void CallPrivateConstructor() |
87 |
| - { |
88 |
| - Class c1 = PrivateCtor(1); |
89 |
| - |
90 |
| - Class c2 = (Class)RuntimeHelpers.GetUninitializedObject(typeof(Class)); |
91 |
| - |
92 |
| - PrivateCtorAsMethod(c2, 2); |
93 |
| - |
94 |
| - [UnsafeAccessor(UnsafeAccessorKind.Constructor)] |
95 |
| - extern static Class PrivateCtor(int i); |
96 |
| - |
97 |
| - [UnsafeAccessor(UnsafeAccessorKind.Method, Name = ".ctor")] |
98 |
| - extern static void PrivateCtorAsMethod(Class c, int i); |
99 |
| - |
100 |
| - } |
101 |
| - public void CallPrivateMethod(Class c) |
102 |
| - { |
103 |
| - PrivateMethod(c); |
104 |
| - |
105 |
| - [UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(PrivateMethod))] |
106 |
| - extern static void PrivateMethod(Class c); |
107 |
| - } |
108 |
| - public void GetPrivateProperty(Class c) |
109 |
| - { |
110 |
| - int f = GetPrivateProperty(c); |
111 |
| - |
112 |
| - [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_PrivateProperty")] |
113 |
| - extern static int GetPrivateProperty(Class c); |
114 |
| - } |
115 |
| - public void GetSetPrivateField(Class c) |
116 |
| - { |
117 |
| - ref int f = ref GetSetPrivateField(c); |
118 |
| - |
119 |
| - [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "PrivateField")] |
120 |
| - extern static ref int GetSetPrivateField(Class c); |
121 |
| - } |
| 63 | + <code language="csharp"> |
| 64 | + public class Class |
| 65 | + { |
| 66 | + static void StaticPrivateMethod() { } |
| 67 | + static int StaticPrivateField; |
| 68 | + Class(int i) { PrivateField = i; } |
| 69 | + void PrivateMethod() { } |
| 70 | + int PrivateField; |
| 71 | + int PrivateProperty { get => PrivateField; } |
| 72 | + } |
| 73 | + |
| 74 | + public void CallStaticPrivateMethod() |
| 75 | + { |
| 76 | + StaticPrivateMethod(null); |
| 77 | + |
| 78 | + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = nameof(StaticPrivateMethod))] |
| 79 | + extern static void StaticPrivateMethod(Class c); |
| 80 | + } |
| 81 | + public void GetSetStaticPrivateField() |
| 82 | + { |
| 83 | + ref int f = ref GetSetStaticPrivateField(null); |
| 84 | + |
| 85 | + [UnsafeAccessor(UnsafeAccessorKind.StaticField, Name = "StaticPrivateField")] |
| 86 | + extern static ref int GetSetStaticPrivateField(Class c); |
| 87 | + } |
| 88 | + public void CallPrivateConstructor() |
| 89 | + { |
| 90 | + Class c1 = PrivateCtor(1); |
| 91 | + |
| 92 | + Class c2 = (Class)RuntimeHelpers.GetUninitializedObject(typeof(Class)); |
| 93 | + |
| 94 | + PrivateCtorAsMethod(c2, 2); |
| 95 | + |
| 96 | + [UnsafeAccessor(UnsafeAccessorKind.Constructor)] |
| 97 | + extern static Class PrivateCtor(int i); |
| 98 | + |
| 99 | + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = ".ctor")] |
| 100 | + extern static void PrivateCtorAsMethod(Class c, int i); |
| 101 | + |
| 102 | + } |
| 103 | + public void CallPrivateMethod(Class c) |
| 104 | + { |
| 105 | + PrivateMethod(c); |
| 106 | + |
| 107 | + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(PrivateMethod))] |
| 108 | + extern static void PrivateMethod(Class c); |
| 109 | + } |
| 110 | + public void GetPrivateProperty(Class c) |
| 111 | + { |
| 112 | + int f = GetPrivateProperty(c); |
| 113 | + |
| 114 | + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_PrivateProperty")] |
| 115 | + extern static int GetPrivateProperty(Class c); |
| 116 | + } |
| 117 | + public void GetSetPrivateField(Class c) |
| 118 | + { |
| 119 | + ref int f = ref GetSetPrivateField(c); |
| 120 | + |
| 121 | + [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "PrivateField")] |
| 122 | + extern static ref int GetSetPrivateField(Class c); |
| 123 | + } |
| 124 | + |
| 125 | + // Generic example |
| 126 | + public class Class<T> |
| 127 | + { |
| 128 | + private T _field; |
| 129 | + private void M(T t) { } |
| 130 | + private void GM<U>(U u) { } |
| 131 | + private void GMWithConstraints<U, V>(U u, V v) where U : V, IEquatable<U> { } |
| 132 | + } |
| 133 | + |
| 134 | + class Accessors<V> |
| 135 | + { |
| 136 | + [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_field")] |
| 137 | + public extern static ref V GetSetPrivateField(Class<V> c); |
| 138 | + |
| 139 | + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "M")] |
| 140 | + public extern static void CallM(Class<V> c, V v); |
| 141 | + |
| 142 | + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "GM")] |
| 143 | + public extern static void CallGM<X>(Class<V> c, X x); |
| 144 | + |
| 145 | + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "GMWithConstraints")] |
| 146 | + public extern static void CallGMWithConstraints<X, Y>(Class<V> c, X x, Y y) where X : Y, IEquatable<X>; |
| 147 | + } |
| 148 | + |
| 149 | + public void AccessGenericType(Class<int> c) |
| 150 | + { |
| 151 | + ref int f = ref Accessors<int>.GetSetPrivateField(c); |
| 152 | + |
| 153 | + Accessors<int>.CallM(c, 1); |
| 154 | + |
| 155 | + Accessors<int>.CallGM<string>(c, string.Empty); |
| 156 | + |
| 157 | + Accessors<int>.CallGMWithConstraints<string, object>(c, string.Empty, new object()); |
| 158 | + } |
122 | 159 | </code>
|
123 | 160 | </example>
|
124 | 161 | </Docs>
|
@@ -186,7 +223,7 @@ By default, the attributed method's name dictates the name of the method/field.
|
186 | 223 | <Docs>
|
187 | 224 | <summary>Gets or sets the name of the member to which access is provided.</summary>
|
188 | 225 | <value>To be added.</value>
|
189 |
| - <remarks>The name defaults to the annotated method name if not specified. |
| 226 | + <remarks>The name defaults to the annotated method name if not specified. |
190 | 227 | The name must be unset/<code>null</code> for <see cref="F:System.Runtime.CompilerServices.UnsafeAccessorKind.Constructor" />.</remarks>
|
191 | 228 | </Docs>
|
192 | 229 | </Member>
|
|
0 commit comments