From bcb0f8ef411308e30e45d7310071660c6dbf8ac9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Mar 2026 14:17:12 +0000 Subject: [PATCH 1/5] Initial plan From ea7c7f775b128d59699229b57c3970974fdca41f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Mar 2026 14:19:28 +0000 Subject: [PATCH 2/5] Add 'Access static members' section to AssemblyLoadContext article Co-authored-by: BillWagner <493969+BillWagner@users.noreply.github.com> --- .../understanding-assemblyloadcontext.md | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/docs/core/dependency-loading/understanding-assemblyloadcontext.md b/docs/core/dependency-loading/understanding-assemblyloadcontext.md index 0af434e7f51e2..ab702d962a925 100644 --- a/docs/core/dependency-loading/understanding-assemblyloadcontext.md +++ b/docs/core/dependency-loading/understanding-assemblyloadcontext.md @@ -1,8 +1,9 @@ --- title: About AssemblyLoadContext - .NET description: Key concepts to understand the purpose and behavior of AssemblyLoadContext in .NET. -ms.date: 08/18/2022 +ms.date: 03/05/2026 author: sdmaclea +ai-usage: ai-assisted --- # About System.Runtime.Loader.AssemblyLoadContext @@ -109,3 +110,39 @@ There are two design patterns for solving these type conversion issues. 1. Use common shared types. This shared type can either be a primitive runtime type, or it can involve creating a new shared type in a shared assembly. Often the shared type is an [interface](../../csharp/language-reference/keywords/interface.md) defined in an application assembly. For more information, read about [how dependencies are shared](#shared-dependencies). 2. Use marshalling techniques to convert from one type to another. + +## Access static members + +Types loaded into a custom are isolated from types in other contexts, so you must use reflection to access their static members from outside the context. + +For example, consider this static class in a dynamically loaded assembly: + +```csharp +public static class Paths +{ + public static DirectoryInfo RootIO { get; private set; } +} +``` + +Use to read the property value. Pass `null` as the first argument because static members don't require an instance: + +```csharp +// Get the type from the loaded assembly +Type pathsType = loadedAssembly.GetType("Paths"); + +// Use PropertyInfo to access a static property +PropertyInfo rootIoProperty = pathsType.GetProperty("RootIO"); +DirectoryInfo rootIo = (DirectoryInfo)rootIoProperty.GetValue(null); +``` + +Alternatively, C# compiles property accessors into methods with `get_` and `set_` prefixes. You can call these backing methods directly using : + +```csharp +MethodInfo getRootIo = pathsType.GetMethod("get_RootIO"); +DirectoryInfo rootIo = (DirectoryInfo)getRootIo.Invoke(null, null); +``` + +The same pattern applies to static fields, which you can access via and , and to static methods, which you invoke with . + +> [!NOTE] +> If you retrieve a value whose type is defined in the loaded assembly, you might encounter type-conversion issues when you try to cast it in the calling context. For more information, see [Type-conversion issues](#type-conversion-issues). From 6ff7f6dc2bf59333a9df9fdb03cbad8c5801e6ea Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 6 Mar 2026 09:54:30 -0500 Subject: [PATCH 3/5] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../understanding-assemblyloadcontext.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/core/dependency-loading/understanding-assemblyloadcontext.md b/docs/core/dependency-loading/understanding-assemblyloadcontext.md index ab702d962a925..b903533b5810f 100644 --- a/docs/core/dependency-loading/understanding-assemblyloadcontext.md +++ b/docs/core/dependency-loading/understanding-assemblyloadcontext.md @@ -128,17 +128,20 @@ Use : ```csharp -MethodInfo getRootIo = pathsType.GetMethod("get_RootIO"); +MethodInfo getRootIo = pathsType.GetMethod("get_RootIO") + ?? throw new InvalidOperationException("Accessor method 'get_RootIO' was not found on type 'Paths'."); DirectoryInfo rootIo = (DirectoryInfo)getRootIo.Invoke(null, null); ``` From 92135ef75fb39783dcd7aa6bdb576d7f15080262 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Mar 2026 14:57:11 +0000 Subject: [PATCH 4/5] Fix accessor method section: use BindingFlags for non-public accessors Co-authored-by: BillWagner <493969+BillWagner@users.noreply.github.com> --- .../understanding-assemblyloadcontext.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/core/dependency-loading/understanding-assemblyloadcontext.md b/docs/core/dependency-loading/understanding-assemblyloadcontext.md index b903533b5810f..41cca3e555485 100644 --- a/docs/core/dependency-loading/understanding-assemblyloadcontext.md +++ b/docs/core/dependency-loading/understanding-assemblyloadcontext.md @@ -137,12 +137,20 @@ PropertyInfo rootIoProperty = pathsType.GetProperty("RootIO") DirectoryInfo rootIo = (DirectoryInfo)rootIoProperty.GetValue(null); ``` -Alternatively, C# compiles property accessors into methods with `get_` and `set_` prefixes. You can call these backing methods directly using : +Alternatively, C# compiles property accessors into methods with `get_` and `set_` prefixes. You can call these accessor methods directly using . However, only returns public methods. When an accessor is non-public (such as the `private set` in the example), you must use the overload that accepts : ```csharp +// Public getter — no BindingFlags needed MethodInfo getRootIo = pathsType.GetMethod("get_RootIO") ?? throw new InvalidOperationException("Accessor method 'get_RootIO' was not found on type 'Paths'."); DirectoryInfo rootIo = (DirectoryInfo)getRootIo.Invoke(null, null); + +// Non-public setter — must use BindingFlags +MethodInfo setRootIo = pathsType.GetMethod( + "set_RootIO", + BindingFlags.Static | BindingFlags.NonPublic) + ?? throw new InvalidOperationException("Accessor method 'set_RootIO' was not found on type 'Paths'."); +setRootIo.Invoke(null, new object[] { newValue }); ``` The same pattern applies to static fields, which you can access via and , and to static methods, which you invoke with . From e9a5c65a31d6a15091a5ae60f7e5d29b52f847e0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Mar 2026 14:59:21 +0000 Subject: [PATCH 5/5] Use fully qualified type name in GetType example to handle namespaced types Co-authored-by: BillWagner <493969+BillWagner@users.noreply.github.com> --- .../understanding-assemblyloadcontext.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/core/dependency-loading/understanding-assemblyloadcontext.md b/docs/core/dependency-loading/understanding-assemblyloadcontext.md index 41cca3e555485..0ce60f1ba14e2 100644 --- a/docs/core/dependency-loading/understanding-assemblyloadcontext.md +++ b/docs/core/dependency-loading/understanding-assemblyloadcontext.md @@ -118,22 +118,24 @@ Types loaded into a custom are For example, consider this static class in a dynamically loaded assembly: ```csharp +namespace MyPlugin; + public static class Paths { public static DirectoryInfo RootIO { get; private set; } } ``` -Use to read the property value. Pass `null` as the first argument because static members don't require an instance: +Use to read the property value. Pass `null` as the first argument because static members don't require an instance. Pass the fully qualified type name (including the namespace) to : ```csharp -// Get the type from the loaded assembly -Type pathsType = loadedAssembly.GetType("Paths") - ?? throw new InvalidOperationException("Type 'Paths' not found in loaded assembly."); +// Get the type from the loaded assembly using the fully qualified name +Type pathsType = loadedAssembly.GetType("MyPlugin.Paths") + ?? throw new InvalidOperationException("Type 'MyPlugin.Paths' not found in loaded assembly."); // Use PropertyInfo to access a static property PropertyInfo rootIoProperty = pathsType.GetProperty("RootIO") - ?? throw new InvalidOperationException("Property 'RootIO' was not found on type 'Paths'."); + ?? throw new InvalidOperationException("Property 'RootIO' was not found on type 'MyPlugin.Paths'."); DirectoryInfo rootIo = (DirectoryInfo)rootIoProperty.GetValue(null); ``` @@ -142,14 +144,14 @@ Alternatively, C# compiles property accessors into methods with `get_` and `set_ ```csharp // Public getter — no BindingFlags needed MethodInfo getRootIo = pathsType.GetMethod("get_RootIO") - ?? throw new InvalidOperationException("Accessor method 'get_RootIO' was not found on type 'Paths'."); + ?? throw new InvalidOperationException("Accessor method 'get_RootIO' was not found on type 'MyPlugin.Paths'."); DirectoryInfo rootIo = (DirectoryInfo)getRootIo.Invoke(null, null); // Non-public setter — must use BindingFlags MethodInfo setRootIo = pathsType.GetMethod( "set_RootIO", BindingFlags.Static | BindingFlags.NonPublic) - ?? throw new InvalidOperationException("Accessor method 'set_RootIO' was not found on type 'Paths'."); + ?? throw new InvalidOperationException("Accessor method 'set_RootIO' was not found on type 'MyPlugin.Paths'."); setRootIo.Invoke(null, new object[] { newValue }); ```