From 828fb52390fb2985082d276022515429f472d935 Mon Sep 17 00:00:00 2001 From: sonyps5201314 Date: Wed, 22 Oct 2025 23:33:03 +0800 Subject: [PATCH] `IsBaseCtorCall` no longer checks the number of parameters. Otherwise, it would cause the translation of the `DeserializationException` type in `https://github.com/restsharp/RestSharp/blob/dev/src/RestSharp/Serializers/DeseralizationException.cs` to fail, as it is a primary constructor declaration that calls a base constructor with two arguments. Additionally, dotPeek's `IsPrimaryConstructorFast` function has been introduced. This is because, after the aforementioned modification to `IsBaseCtorCall`, the `NamedParameter` type in RestSharp was being incorrectly identified as a primary constructor. Without this correction, it would lead to many compilation errors. --- .../CSharp/RecordDecompiler.cs | 57 ++++++++++++++++++- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs b/ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs index 2b623c094..fe9c1f01e 100644 --- a/ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs @@ -20,6 +20,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Reflection; using System.Reflection.Metadata; using System.Threading; @@ -159,6 +160,50 @@ namespace ICSharpCode.Decompiler.CSharp } } + public static bool IsPrimaryConstructorFast(IMethod constructor, bool isStruct, bool recordPrimaryConstructor) + { + if (constructor.Parameters.Count == 0 && (isStruct || !recordPrimaryConstructor)) + { + return false; + } + + //下面注释的这一段就暂时不翻译了,因为目前在ILSpy中无法进行翻译, + //因为在ILSpy中RecordDecompiler.DetectPrimaryConstructor会先于TransformFieldAndConstructorInitializers执行, + //而在dotPeek中是先执行ExtractInstanceCtorInitializerTransformation再执行DetectPrimaryConstructorTransformation的 + /* + IConstructorInitializer constructorInitializer = constructor.ConstructorInitializer; + if (constructorInitializer != null && constructorInitializer.Target is IThisReferenceExpression) + { + return false; + } + */ + if (!constructor.IsAbstract && constructor.DeclaringType.Kind != TypeKind.Interface && !constructor.HasBody)//IsExtern + { + return false; + } + if (constructor.DeclaringType.GetDefinition()?.IsAbstract ?? false) + { + var module = constructor.ParentModule as MetadataModule; + var handle = (MethodDefinitionHandle)constructor.MetadataToken; + var metadata = module.metadata; + var def = metadata.GetMethodDefinition(handle); + var attributes = def.Attributes; + if (!attributes.HasFlag(MethodAttributes.Family))//IsFamily + { + return false; + } + } + else if (!(constructor.Accessibility == Accessibility.Public))//IsPublic + { + return false; + } + if (constructor is VarArgInstanceMethod) + { + return false; + } + return true; + } + IMethod DetectPrimaryConstructor() { if (recordTypeDef.IsRecord) @@ -190,11 +235,12 @@ namespace ICSharpCode.Decompiler.CSharp return null; //判定主构造函数的唯一准则是: - //首先它不能是拷贝构造函数, + //首先它不能是拷贝构造函数,且能通过IsPrimaryConstructorFast的判定逻辑, //然后这个构造函数中前面部分都是类成员属性/字段赋值语句, //之后是调用基类构造函数的语句即"base..ctor(...);", //再之后就是返回语句了,即"base..ctor(...);"之后不存在任何其他初始化语句。 - //且主构造函数的参数和类成员之间无任何对应关系! + //注意:不存在捕获参数的情况下,主构造函数的参数和类成员之间无任何对应关系! + //注意:目前即使一个函数的原始代码形式是常规构造函数,但是如果它符合本IsPrimaryConstructor函数的判定规则也会将它翻译成主构造函数形式 bool IsPrimaryConstructor(IMethod method, IMethod unspecializedMethod) { Debug.Assert(method.IsConstructor); @@ -202,6 +248,9 @@ namespace ICSharpCode.Decompiler.CSharp if (IsCopyConstructor(method)) return false; + if (!IsPrimaryConstructorFast(method, isStruct, false)) + return false; + var body = DecompileBody(method); if (body == null) return false; @@ -435,7 +484,7 @@ namespace ICSharpCode.Decompiler.CSharp return false; if (!object.Equals(baseCtorCall.Method.DeclaringType, baseClass)) return false; - if (baseCtorCall.Arguments.Count != (isInheritedRecord ? 2 : 1)) + if (baseCtorCall.Arguments.Count <= 0) return false; if (!baseCtorCall.Arguments[0].MatchLdThis()) return false; @@ -471,6 +520,8 @@ namespace ICSharpCode.Decompiler.CSharp { return false; } + if (baseCtorCall.Arguments.Count != (isInheritedRecord ? 2 : 1)) + return false; if (isInheritedRecord) { if (!baseCtorCall.Arguments[1].MatchLdLoc(other))