Skip to content

Commit ad09e94

Browse files
CopilotBillWagnerCopilot
authored
docs: explain how to access static members of types loaded in AssemblyLoadContext (#52093)
* Initial plan * Add 'Access static members' section to AssemblyLoadContext article Co-authored-by: BillWagner <493969+BillWagner@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix accessor method section: use BindingFlags for non-public accessors Co-authored-by: BillWagner <493969+BillWagner@users.noreply.github.com> * Use fully qualified type name in GetType example to handle namespaced types Co-authored-by: BillWagner <493969+BillWagner@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: BillWagner <493969+BillWagner@users.noreply.github.com> Co-authored-by: Bill Wagner <wiwagn@microsoft.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent b203a24 commit ad09e94

1 file changed

Lines changed: 51 additions & 1 deletion

File tree

docs/core/dependency-loading/understanding-assemblyloadcontext.md

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
---
22
title: About AssemblyLoadContext - .NET
33
description: Key concepts to understand the purpose and behavior of AssemblyLoadContext in .NET.
4-
ms.date: 08/18/2022
4+
ms.date: 03/05/2026
55
author: sdmaclea
6+
ai-usage: ai-assisted
67
---
78
# About System.Runtime.Loader.AssemblyLoadContext
89

@@ -109,3 +110,52 @@ There are two design patterns for solving these type conversion issues.
109110
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).
110111

111112
2. Use marshalling techniques to convert from one type to another.
113+
114+
## Access static members
115+
116+
Types loaded into a custom <xref:System.Runtime.Loader.AssemblyLoadContext> are isolated from types in other contexts, so you must use reflection to access their static members from outside the context.
117+
118+
For example, consider this static class in a dynamically loaded assembly:
119+
120+
```csharp
121+
namespace MyPlugin;
122+
123+
public static class Paths
124+
{
125+
public static DirectoryInfo RootIO { get; private set; }
126+
}
127+
```
128+
129+
Use <xref:System.Reflection.PropertyInfo.GetValue%2A?displayProperty=nameWithType> 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 <xref:System.Reflection.Assembly.GetType(System.String)?displayProperty=nameWithType>:
130+
131+
```csharp
132+
// Get the type from the loaded assembly using the fully qualified name
133+
Type pathsType = loadedAssembly.GetType("MyPlugin.Paths")
134+
?? throw new InvalidOperationException("Type 'MyPlugin.Paths' not found in loaded assembly.");
135+
136+
// Use PropertyInfo to access a static property
137+
PropertyInfo rootIoProperty = pathsType.GetProperty("RootIO")
138+
?? throw new InvalidOperationException("Property 'RootIO' was not found on type 'MyPlugin.Paths'.");
139+
DirectoryInfo rootIo = (DirectoryInfo)rootIoProperty.GetValue(null);
140+
```
141+
142+
Alternatively, C# compiles property accessors into methods with `get_` and `set_` prefixes. You can call these accessor methods directly using <xref:System.Type.GetMethod%2A?displayProperty=nameWithType>. However, <xref:System.Type.GetMethod(System.String)?displayProperty=nameWithType> 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 <xref:System.Reflection.BindingFlags>:
143+
144+
```csharp
145+
// Public getter — no BindingFlags needed
146+
MethodInfo getRootIo = pathsType.GetMethod("get_RootIO")
147+
?? throw new InvalidOperationException("Accessor method 'get_RootIO' was not found on type 'MyPlugin.Paths'.");
148+
DirectoryInfo rootIo = (DirectoryInfo)getRootIo.Invoke(null, null);
149+
150+
// Non-public setter — must use BindingFlags
151+
MethodInfo setRootIo = pathsType.GetMethod(
152+
"set_RootIO",
153+
BindingFlags.Static | BindingFlags.NonPublic)
154+
?? throw new InvalidOperationException("Accessor method 'set_RootIO' was not found on type 'MyPlugin.Paths'.");
155+
setRootIo.Invoke(null, new object[] { newValue });
156+
```
157+
158+
The same pattern applies to static fields, which you can access via <xref:System.Reflection.FieldInfo.GetValue%2A?displayProperty=nameWithType> and <xref:System.Reflection.FieldInfo.SetValue%2A?displayProperty=nameWithType>, and to static methods, which you invoke with <xref:System.Reflection.MethodBase.Invoke%2A?displayProperty=nameWithType>.
159+
160+
> [!NOTE]
161+
> 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).

0 commit comments

Comments
 (0)