-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Add XML doc comments to DynamicMethod #124407
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
richlander
wants to merge
12
commits into
dotnet:main
from
richlander:dev/richlander/dynamicmethod-xmldocs
Closed
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
9c7e7db
Add XML doc comments to DynamicMethod from dotnet-api-docs
richlander 35e5e4d
Add DynamicMethod samples file and update code references
richlander 07b69b4
Rewrite DynamicMethod samples as runnable file-based app
richlander de654f6
Add Overview and CtorOwnerType samples, restore code links
richlander 9ce8b3c
Add samples.json for DocId-to-sample mapping
richlander f026749
Add titles to samples.json entries
richlander a3b3f28
Regenerate DynamicMethod code tags via merge tool with samples.json
richlander 18957d6
Rename sample regions and fix paths in samples.json
richlander 7422441
Regenerate DynamicMethod.cs — clean example blocks
richlander 46cfb97
Add Directory.Build.props/targets for runnable samples
richlander 8a8f318
Add CreateDelegate, Invoke, and GetILGenerator samples
richlander 22a88a6
Switch DynamicMethod samples from regions to methods
richlander File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
11 changes: 11 additions & 0 deletions
11
src/libraries/System.Private.CoreLib/samples/Directory.Build.props
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| <Project> | ||
| <!-- Stop inheriting repo-wide settings that break file-based app samples. --> | ||
| <PropertyGroup> | ||
| <TargetFramework>net11.0</TargetFramework> | ||
| <PublishAot>false</PublishAot> | ||
| <IsAotCompatible>false</IsAotCompatible> | ||
| <IsSourceProject>false</IsSourceProject> | ||
| <IsReferenceAssemblyProject>false</IsReferenceAssemblyProject> | ||
| <TreatWarningsAsErrors>false</TreatWarningsAsErrors> | ||
| </PropertyGroup> | ||
| </Project> |
2 changes: 2 additions & 0 deletions
2
src/libraries/System.Private.CoreLib/samples/Directory.Build.targets
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| <Project> | ||
| </Project> |
57 changes: 57 additions & 0 deletions
57
...ries/System.Private.CoreLib/samples/System/Reflection/Emit/DynamicMethod.CtorOwnerType.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
| // Example: Create a DynamicMethod with an owner type to access private members. | ||
| // Shows CreateDelegate with a bound instance (instance-style invocation). | ||
| // Run: dotnet run DynamicMethod.CtorOwnerType.cs | ||
|
|
||
| using System.Reflection; | ||
| using System.Reflection.Emit; | ||
|
|
||
| OwnerTypeAccess(); | ||
|
|
||
| Console.WriteLine("Passed."); | ||
| return 0; | ||
|
|
||
| void OwnerTypeAccess() | ||
| { | ||
| // A DynamicMethod associated with a type can access its private members. | ||
| DynamicMethod changeID = new( | ||
| "", typeof(int), [typeof(Example), typeof(int)], typeof(Example)); | ||
|
|
||
| // Get a FieldInfo for the private field 'id'. | ||
| FieldInfo fid = typeof(Example).GetField("id", BindingFlags.NonPublic | BindingFlags.Instance)!; | ||
|
|
||
| ILGenerator ilg = changeID.GetILGenerator(); | ||
| // Push current value of 'id' onto the stack. | ||
| ilg.Emit(OpCodes.Ldarg_0); | ||
| ilg.Emit(OpCodes.Ldfld, fid); | ||
| // Store the new value. | ||
| ilg.Emit(OpCodes.Ldarg_0); | ||
| ilg.Emit(OpCodes.Ldarg_1); | ||
| ilg.Emit(OpCodes.Stfld, fid); | ||
| // Return the old value. | ||
| ilg.Emit(OpCodes.Ret); | ||
|
|
||
| // Static-style delegate: takes (Example, int), returns old id. | ||
| var setId = changeID.CreateDelegate<Func<Example, int, int>>(); | ||
|
|
||
| Example ex = new(42); | ||
| int oldId = setId(ex, 1492); | ||
| Console.WriteLine($"Previous id: {oldId}, new id: {ex.ID}"); | ||
|
|
||
| // Instance-style delegate: bind to a specific Example instance. | ||
| var setBound = (Func<int, int>)changeID.CreateDelegate(typeof(Func<int, int>), ex); | ||
| oldId = setBound(2700); | ||
| Console.WriteLine($"Previous id: {oldId}, new id: {ex.ID}"); | ||
|
|
||
| // Verify | ||
| if (ex.ID != 2700) | ||
| throw new Exception($"FAIL: expected 2700, got {ex.ID}"); | ||
| } | ||
|
|
||
| // Helper types | ||
| public class Example(int id) | ||
| { | ||
| private int id = id; | ||
| public int ID => id; | ||
| } | ||
92 changes: 92 additions & 0 deletions
92
...libraries/System.Private.CoreLib/samples/System/Reflection/Emit/DynamicMethod.Examples.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
| // Runnable examples for DynamicMethod XML doc comments. | ||
| // Each local function is a self-contained sample referenced by <code> tags in DynamicMethod.cs. | ||
| // Run: dotnet run DynamicMethod.Examples.cs | ||
|
|
||
| using System.Globalization; | ||
| using System.Reflection; | ||
| using System.Reflection.Emit; | ||
|
|
||
| MetadataAndProperties(); | ||
| DefineParameterAndGetParameters(); | ||
| GetILGeneratorAndInvoke(); | ||
|
|
||
| Console.WriteLine("All examples passed."); | ||
| return 0; | ||
|
|
||
| void MetadataAndProperties() | ||
| { | ||
| // Create a dynamic method associated with a module. | ||
| DynamicMethod hello = new("Hello", typeof(int), [typeof(string), typeof(int)], typeof(string).Module); | ||
|
|
||
| // Name: the name specified at creation. | ||
| Console.WriteLine($"Name: {hello.Name}"); | ||
|
|
||
| // DeclaringType is always null for dynamic methods. | ||
| Console.WriteLine($"DeclaringType: {hello.DeclaringType?.ToString() ?? "(null)"}"); | ||
|
|
||
| // ReflectedType is always null for dynamic methods. | ||
| Console.WriteLine($"ReflectedType: {hello.ReflectedType?.ToString() ?? "(null)"}"); | ||
|
|
||
| // Module: the module the dynamic method is associated with. | ||
| Console.WriteLine($"Module: {hello.Module}"); | ||
|
|
||
| // Attributes are always Public | Static. | ||
| Console.WriteLine($"Attributes: {hello.Attributes}"); | ||
|
|
||
| // CallingConvention is always Standard. | ||
| Console.WriteLine($"CallingConvention: {hello.CallingConvention}"); | ||
|
|
||
| // ReturnType: the return type specified at creation. | ||
| Console.WriteLine($"ReturnType: {hello.ReturnType}"); | ||
|
|
||
| // ReturnTypeCustomAttributes: no way to set custom attributes on the return type. | ||
| ICustomAttributeProvider caProvider = hello.ReturnTypeCustomAttributes; | ||
| object[] returnAttributes = caProvider.GetCustomAttributes(true); | ||
| Console.WriteLine($"Return type custom attributes: {returnAttributes.Length}"); | ||
|
|
||
| // InitLocals defaults to true — local variables are zero-initialized. | ||
| Console.WriteLine($"InitLocals: {hello.InitLocals}"); | ||
|
|
||
| // ToString returns the method signature (return type, name, parameter types). | ||
| Console.WriteLine($"ToString: {hello.ToString()}"); | ||
| } | ||
|
|
||
| void DefineParameterAndGetParameters() | ||
| { | ||
| DynamicMethod hello = new("Hello", typeof(int), [typeof(string), typeof(int)], typeof(string).Module); | ||
|
|
||
| // DefineParameter adds metadata such as name and attributes. | ||
| // Parameter positions are 1-based; position 0 refers to the return value. | ||
| hello.DefineParameter(1, ParameterAttributes.In, "message"); | ||
| hello.DefineParameter(2, ParameterAttributes.In, "valueToReturn"); | ||
|
|
||
| // GetParameters retrieves the parameter info. | ||
| ParameterInfo[] parameters = hello.GetParameters(); | ||
| foreach (ParameterInfo p in parameters) | ||
| Console.WriteLine($" Param: {p.Name}, {p.ParameterType}, {p.Attributes}"); | ||
| } | ||
|
|
||
| void GetILGeneratorAndInvoke() | ||
| { | ||
| DynamicMethod hello = new("Hello", typeof(int), [typeof(string), typeof(int)], typeof(string).Module); | ||
| MethodInfo writeString = typeof(Console).GetMethod("WriteLine", [typeof(string)])!; | ||
|
|
||
| // GetILGenerator returns an ILGenerator for emitting the method body. | ||
| ILGenerator il = hello.GetILGenerator(); | ||
| il.Emit(OpCodes.Ldarg_0); // push first arg (string) | ||
| il.EmitCall(OpCodes.Call, writeString, null); // Console.WriteLine(string) | ||
| il.Emit(OpCodes.Ldarg_1); // push second arg (int) | ||
| il.Emit(OpCodes.Ret); // return it | ||
|
|
||
| // CreateDelegate produces a strongly-typed delegate for the dynamic method. | ||
| Func<string, int, int> hi = hello.CreateDelegate<Func<string, int, int>>(); | ||
| int retval = hi("Hello from delegate!", 42); | ||
| Console.WriteLine($"Delegate returned: {retval}"); | ||
|
|
||
| // Invoke calls the dynamic method via reflection (slower than a delegate). | ||
| object? objRet = hello.Invoke(null, BindingFlags.ExactBinding, null, | ||
| ["Hello from Invoke!", 99], CultureInfo.InvariantCulture); | ||
| Console.WriteLine($"Invoke returned: {objRet}"); | ||
| } |
42 changes: 42 additions & 0 deletions
42
...libraries/System.Private.CoreLib/samples/System/Reflection/Emit/DynamicMethod.Overview.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
| // Example: Create a DynamicMethod, emit IL, and execute via delegate and Invoke. | ||
| // Referenced by DynamicMethod class overview and GetILGenerator/constructor docs. | ||
| // Run: dotnet run DynamicMethod.Overview.cs | ||
|
|
||
| using System.Reflection; | ||
| using System.Reflection.Emit; | ||
|
|
||
| CreateAndInvoke(); | ||
|
|
||
| Console.WriteLine("Passed."); | ||
| return 0; | ||
|
|
||
| void CreateAndInvoke() | ||
| { | ||
| // Create a dynamic method with return type int and two parameters (string, int). | ||
| DynamicMethod hello = new("Hello", typeof(int), [typeof(string), typeof(int)], typeof(string).Module); | ||
|
|
||
| // Emit a body: print the string argument, then return the int argument. | ||
| MethodInfo writeString = typeof(Console).GetMethod("WriteLine", [typeof(string)])!; | ||
| ILGenerator il = hello.GetILGenerator(); | ||
| il.Emit(OpCodes.Ldarg_0); | ||
| il.EmitCall(OpCodes.Call, writeString, null); | ||
| il.Emit(OpCodes.Ldarg_1); | ||
| il.Emit(OpCodes.Ret); | ||
|
|
||
| // Create a delegate that represents the dynamic method. | ||
| Func<string, int, int> hi = hello.CreateDelegate<Func<string, int, int>>(); | ||
|
|
||
| // Execute via delegate. | ||
| int retval = hi("Hello, World!", 42); | ||
| Console.WriteLine($"Delegate returned: {retval}"); | ||
|
|
||
| // Execute via Invoke (slower — requires boxing and array allocation). | ||
| object? objRet = hello.Invoke(null, ["Hello via Invoke!", 99]); | ||
| Console.WriteLine($"Invoke returned: {objRet}"); | ||
|
|
||
| // Verify results | ||
| if (retval != 42 || objRet is not 99) | ||
| throw new Exception("FAIL: unexpected return values"); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| { | ||
| "T:System.Reflection.Emit.DynamicMethod": { "file": "System/Reflection/Emit/DynamicMethod.Overview.cs", "method": "CreateAndInvoke", "title": "Creating and invoking a DynamicMethod" }, | ||
| "M:System.Reflection.Emit.DynamicMethod.#ctor(System.String,System.Type,System.Type[],System.Reflection.Module)": { "file": "System/Reflection/Emit/DynamicMethod.Overview.cs", "method": "CreateAndInvoke", "title": "Creating a DynamicMethod associated with a module" }, | ||
| "M:System.Reflection.Emit.DynamicMethod.#ctor(System.String,System.Type,System.Type[],System.Type)": { "file": "System/Reflection/Emit/DynamicMethod.CtorOwnerType.cs", "method": "OwnerTypeAccess", "title": "Creating a DynamicMethod with an owner type" }, | ||
| "P:System.Reflection.Emit.DynamicMethod.Name": { "file": "System/Reflection/Emit/DynamicMethod.Examples.cs", "method": "MetadataAndProperties", "title": "DynamicMethod metadata properties" }, | ||
| "P:System.Reflection.Emit.DynamicMethod.DeclaringType": { "file": "System/Reflection/Emit/DynamicMethod.Examples.cs", "method": "MetadataAndProperties", "title": "DynamicMethod metadata properties" }, | ||
| "P:System.Reflection.Emit.DynamicMethod.ReflectedType": { "file": "System/Reflection/Emit/DynamicMethod.Examples.cs", "method": "MetadataAndProperties", "title": "DynamicMethod metadata properties" }, | ||
| "P:System.Reflection.Emit.DynamicMethod.Module": { "file": "System/Reflection/Emit/DynamicMethod.Examples.cs", "method": "MetadataAndProperties", "title": "DynamicMethod metadata properties" }, | ||
| "P:System.Reflection.Emit.DynamicMethod.Attributes": { "file": "System/Reflection/Emit/DynamicMethod.Examples.cs", "method": "MetadataAndProperties", "title": "DynamicMethod metadata properties" }, | ||
| "P:System.Reflection.Emit.DynamicMethod.CallingConvention": { "file": "System/Reflection/Emit/DynamicMethod.Examples.cs", "method": "MetadataAndProperties", "title": "DynamicMethod metadata properties" }, | ||
| "P:System.Reflection.Emit.DynamicMethod.ReturnType": { "file": "System/Reflection/Emit/DynamicMethod.Examples.cs", "method": "MetadataAndProperties", "title": "DynamicMethod metadata properties" }, | ||
| "P:System.Reflection.Emit.DynamicMethod.ReturnTypeCustomAttributes": { "file": "System/Reflection/Emit/DynamicMethod.Examples.cs", "method": "MetadataAndProperties", "title": "DynamicMethod metadata properties" }, | ||
| "P:System.Reflection.Emit.DynamicMethod.InitLocals": { "file": "System/Reflection/Emit/DynamicMethod.Examples.cs", "method": "MetadataAndProperties", "title": "DynamicMethod metadata properties" }, | ||
| "M:System.Reflection.Emit.DynamicMethod.ToString": { "file": "System/Reflection/Emit/DynamicMethod.Examples.cs", "method": "MetadataAndProperties", "title": "DynamicMethod metadata properties" }, | ||
| "M:System.Reflection.Emit.DynamicMethod.GetParameters": { "file": "System/Reflection/Emit/DynamicMethod.Examples.cs", "method": "DefineParameterAndGetParameters", "title": "Defining and retrieving DynamicMethod parameters" }, | ||
| "M:System.Reflection.Emit.DynamicMethod.DefineParameter(System.Int32,System.Reflection.ParameterAttributes,System.String)": { "file": "System/Reflection/Emit/DynamicMethod.Examples.cs", "method": "DefineParameterAndGetParameters", "title": "Defining and retrieving DynamicMethod parameters" }, | ||
| "M:System.Reflection.Emit.DynamicMethod.GetILGenerator": { "file": "System/Reflection/Emit/DynamicMethod.Examples.cs", "method": "GetILGeneratorAndInvoke", "title": "Emitting IL and invoking a DynamicMethod" }, | ||
| "M:System.Reflection.Emit.DynamicMethod.GetILGenerator(System.Int32)": { "file": "System/Reflection/Emit/DynamicMethod.Examples.cs", "method": "GetILGeneratorAndInvoke", "title": "Emitting IL and invoking a DynamicMethod" }, | ||
| "M:System.Reflection.Emit.DynamicMethod.CreateDelegate(System.Type)": { "file": "System/Reflection/Emit/DynamicMethod.Examples.cs", "method": "GetILGeneratorAndInvoke", "title": "Emitting IL and invoking a DynamicMethod" }, | ||
| "M:System.Reflection.Emit.DynamicMethod.CreateDelegate(System.Type,System.Object)": { "file": "System/Reflection/Emit/DynamicMethod.CtorOwnerType.cs", "method": "OwnerTypeAccess", "title": "Creating a bound delegate from a DynamicMethod" }, | ||
| "M:System.Reflection.Emit.DynamicMethod.Invoke(System.Object,System.Reflection.BindingFlags,System.Reflection.Binder,System.Object[],System.Globalization.CultureInfo)": { "file": "System/Reflection/Emit/DynamicMethod.Examples.cs", "method": "GetILGeneratorAndInvoke", "title": "Emitting IL and invoking a DynamicMethod" } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This field initializer uses the same identifier on both sides (
private int id = id;) inside a primary-constructor type. This is very likely to either fail to compile (self-referential field initializer / name collision) or to not do what’s intended. Consider renaming the field (e.g.,_id) or assigning the primary-constructor parameter to a differently-named backing field/property to make initialization unambiguous and compilable.