From cae466e5b04ed8581e2bae045abeb7bab9295c11 Mon Sep 17 00:00:00 2001 From: sonyps5201314 Date: Tue, 28 Oct 2025 02:26:12 +0800 Subject: [PATCH] Make `ILSpy` support `struct` and `record struct` types declared with a primary constructor and containing other constructors. Here's an example: ```cs public record struct CopilotContextId_RecordStruct(Guid id) { public Guid guid { get; } = id; public CopilotContextId_RecordStruct() : this(Guid.NewGuid()) { } } public struct CopilotContextId_Struct(Guid id) { public Guid guid { get; } = id; public CopilotContextId_Struct() : this(Guid.NewGuid()) { } } ``` --- ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs | 4 ---- .../TransformFieldAndConstructorInitializers.cs | 9 +++++++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs b/ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs index c811485f0..d25c7db5b 100644 --- a/ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs @@ -210,15 +210,11 @@ namespace ICSharpCode.Decompiler.CSharp { if (!settings.UsePrimaryConstructorSyntax) return null; - if (isStruct) - return null; } else { if (!settings.UsePrimaryConstructorSyntaxForNonRecordTypes) return null; - if (isStruct) - return null; } var subst = recordTypeDef.AsParameterizedType().GetSubstitution(); diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs b/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs index b5b7f1aee..227148aea 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs @@ -166,7 +166,12 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms } }; - static readonly AstNode thisCallPattern = new ExpressionStatement(new InvocationExpression(new MemberReferenceExpression(new ThisReferenceExpression(), ".ctor"), new Repeat(new AnyNode()))); + static readonly AstNode thisCallPattern = new ExpressionStatement { + Expression = new Choice { + new InvocationExpression(new MemberReferenceExpression(new ThisReferenceExpression(), ".ctor"), new Repeat(new AnyNode())), + new AssignmentExpression(new ThisReferenceExpression(), AssignmentOperatorType.Assign, new ObjectCreateExpression(new AnyNode(), new Repeat(new AnyNode()))) + } + }; public override void VisitTypeDeclaration(TypeDeclaration typeDeclaration) { @@ -191,7 +196,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms { var ctorMethodDef = instanceCtorsNotChainingWithThis[0].GetSymbol() as IMethod; ITypeDefinition declaringTypeDefinition = ctorMethodDef?.DeclaringTypeDefinition; - if (ctorMethodDef != null && declaringTypeDefinition?.IsReferenceType == false && !declaringTypeDefinition.IsRecord) + if (ctorMethodDef != null && declaringTypeDefinition?.IsReferenceType == false && !declaringTypeDefinition.IsRecord && declaringTypeDefinition.Kind != TypeKind.Struct) return; bool ctorIsUnsafe = instanceCtorsNotChainingWithThis.All(c => c.HasModifier(Modifiers.Unsafe));