diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
index b984447c2..a75d1dfd7 100644
--- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
+++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
@@ -98,6 +98,7 @@
+
@@ -143,6 +144,7 @@
+
diff --git a/ICSharpCode.Decompiler.Tests/IsolatedMethodDecompilationTests.cs b/ICSharpCode.Decompiler.Tests/IsolatedMethodDecompilationTests.cs
new file mode 100644
index 000000000..7fbf62a99
--- /dev/null
+++ b/ICSharpCode.Decompiler.Tests/IsolatedMethodDecompilationTests.cs
@@ -0,0 +1,73 @@
+// Copyright (c) 2026 AlphaSierraPapa for the SharpDevelop Team
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+using System.IO;
+using System.Linq;
+using System.Reflection.PortableExecutable;
+using System.Threading.Tasks;
+
+using ICSharpCode.Decompiler.CSharp;
+using ICSharpCode.Decompiler.Metadata;
+using ICSharpCode.Decompiler.Tests.Helpers;
+using ICSharpCode.Decompiler.TypeSystem;
+
+using NUnit.Framework;
+
+namespace ICSharpCode.Decompiler.Tests
+{
+ ///
+ /// Decompiling a single member in isolation (the "IL with C#" view does this, decompiling one
+ /// method handle at a time) gives the transforms only a partial syntax tree. This is the mirror
+ /// image of the whole-file ILPretty tests: same assembled-IL fixture, but the assertion is about
+ /// one method's output rather than the full module.
+ ///
+ [TestFixture]
+ public class IsolatedMethodDecompilationTests
+ {
+ static readonly string TestCasePath = Tester.TestCasePath + "/IsolatedDecompilation";
+
+ [Test]
+ public async Task StaticConstructorKeepsFieldInitializers()
+ {
+ var ilFile = Path.Combine(TestCasePath, "IsolatedStaticCtor.il");
+ var assembly = await Tester.AssembleIL(ilFile, AssemblerOptions.Library).ConfigureAwait(false);
+
+ var settings = new DecompilerSettings();
+ using var file = new FileStream(assembly, FileMode.Open, FileAccess.Read);
+ var module = new PEFile(assembly, file, PEStreamOptions.PrefetchEntireImage);
+ var targetFramework = module.Metadata.DetectTargetFrameworkId();
+ var resolver = new UniversalAssemblyResolver(assembly, false, targetFramework, null, PEStreamOptions.PrefetchMetadata);
+ resolver.AddSearchDirectory(Tester.RefAssembliesToolset.GetPath(targetFramework));
+ var typeSystem = new DecompilerTypeSystem(module, resolver, settings);
+ var decompiler = new CSharpDecompiler(typeSystem, settings);
+
+ var staticCtor = typeSystem.MainModule.TypeDefinitions
+ .Single(t => t.Name == "C")
+ .Methods.Single(m => m.IsStatic && m.IsConstructor);
+
+ // Decompile just the .cctor handle: the type's field declarations are not part of the
+ // resulting syntax tree, so the static field initializers have nowhere to move to.
+ var code = decompiler.Decompile(staticCtor.MetadataToken).ToString();
+
+ // They must therefore remain as assignments in the constructor body rather than being
+ // dropped (#3774).
+ Assert.That(code, Does.Contain("Number = 42"));
+ Assert.That(code, Does.Contain("Text = \"hello\""));
+ }
+ }
+}
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/IsolatedDecompilation/.gitignore b/ICSharpCode.Decompiler.Tests/TestCases/IsolatedDecompilation/.gitignore
new file mode 100644
index 000000000..d35b79a63
--- /dev/null
+++ b/ICSharpCode.Decompiler.Tests/TestCases/IsolatedDecompilation/.gitignore
@@ -0,0 +1,2 @@
+/*.dll
+/*.pdb
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/IsolatedDecompilation/IsolatedStaticCtor.il b/ICSharpCode.Decompiler.Tests/TestCases/IsolatedDecompilation/IsolatedStaticCtor.il
new file mode 100644
index 000000000..a494a44ae
--- /dev/null
+++ b/ICSharpCode.Decompiler.Tests/TestCases/IsolatedDecompilation/IsolatedStaticCtor.il
@@ -0,0 +1,36 @@
+#define CORE_ASSEMBLY "System.Runtime"
+
+// Regression fixture for #3774. Static field initializers compile into the type's static
+// constructor, and the decompiler normally moves them onto the field declarations. When a single
+// .cctor is decompiled in isolation (as the "IL with C#" view does, via CSharpDecompiler.Decompile
+// of one method handle) those declarations are absent from the partial syntax tree, so the
+// assignments must stay in the constructor body instead of being dropped. The type is
+// 'beforefieldinit' -- the configuration under which the decompiler treats the .cctor stores as
+// movable field initializers, which is what triggered the dropped statement.
+
+.assembly extern CORE_ASSEMBLY
+{
+ .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A )
+ .ver 4:0:0:0
+}
+
+.assembly IsolatedStaticCtor { }
+
+.class public auto ansi beforefieldinit C
+ extends [CORE_ASSEMBLY]System.Object
+{
+ .field public static initonly int32 Number
+ .field public static initonly string Text
+
+ .method private hidebysig specialname rtspecialname static
+ void .cctor () cil managed
+ {
+ .maxstack 8
+
+ ldc.i4.s 42
+ stsfld int32 C::Number
+ ldstr "hello"
+ stsfld string C::Text
+ ret
+ }
+}
diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs b/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs
index 2bc98bbcf..c3b1244c3 100644
--- a/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs
+++ b/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs
@@ -497,8 +497,13 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (!MemberToDeclaringSyntaxNodeMap.TryGetValue(member, out var declaringSyntaxNode))
{
- Debug.Assert(kind is InitializerKind.Primary);
- stmt.Remove();
+ // A primary-constructor parameter assignment whose backing member has no separate
+ // declaration is redundant and dropped. For static/instance initializers a missing
+ // declaration instead means the member is not part of this (partial) syntax tree --
+ // e.g. when a single static constructor is decompiled in isolation -- so the
+ // assignment must remain in the constructor body.
+ if (kind is InitializerKind.Primary)
+ stmt.Remove();
continue;
}