diff --git a/.github/actions/setup-dotnet/action.yaml b/.github/actions/setup-dotnet/action.yaml index e44880788..839f27ae0 100644 --- a/.github/actions/setup-dotnet/action.yaml +++ b/.github/actions/setup-dotnet/action.yaml @@ -14,7 +14,7 @@ runs: using: "composite" steps: # see: https://github.com/actions/setup-dotnet - - uses: actions/setup-dotnet@v4 + - uses: actions/setup-dotnet@v5 with: global-json-file: ${{ inputs.global-json-file }} diff --git a/.github/workflows/_create-release.yaml b/.github/workflows/_create-release.yaml index ec5728191..1c88829c7 100644 --- a/.github/workflows/_create-release.yaml +++ b/.github/workflows/_create-release.yaml @@ -42,10 +42,12 @@ on: jobs: create-release: name: Create Release + permissions: + id-token: write + contents: write env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} # auto generated token GH_REPO: ${{ github.repository }} - NUGET_KEY: ${{ secrets.NUGET_KEY }} runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -56,14 +58,17 @@ jobs: echo "Validation error! 'inputs.release-asset-path' cannot be blank when 'inputs.release-upload' is true." exit 1 - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: ref: ${{ inputs.commit-id }} - uses: ./.github/actions/setup-dotnet # Download(All) Artifacts to $GITHUB_WORKSPACE - - name: donload artifacts - uses: actions/download-artifact@v4 # must sync with actions/upload-artifact@v4 in build-release + - name: download artifacts + uses: actions/download-artifact@v8 # must sync with actions/upload-artifact@v7 in build-release + with: + name: nuget + path: ./nuget - name: Show download aritifacts run: ls -lR - name: Validate package exists in artifact - release assets @@ -140,6 +145,13 @@ jobs: done <<< "${{ inputs.release-asset-path }}" if: ${{ inputs.release-upload }} + - name: NuGet login (OIDC) + id: nuget-login + if: ${{ inputs.nuget-push }} + uses: NuGet/login@v1 + with: + user: ${{ secrets.NUGET_USER }} + # Upload to NuGet - name: Upload to NuGet (DryRun=${{ inputs.dry-run }}) if: ${{ inputs.nuget-push }} @@ -153,9 +165,9 @@ jobs: fi if [[ "${{ inputs.dry-run }}" == "true" ]]; then - echo "(dry run) dotnet nuget push \"${nuget_path}\" --skip-duplicate -s https://api.nuget.org/v3/index.json -k \"${{ env.NUGET_KEY }}\"" + echo "(dry run) dotnet nuget push \"${nuget_path}\" --skip-duplicate -s https://api.nuget.org/v3/index.json -k \"***\"" else - dotnet nuget push "${nuget_path}" --skip-duplicate -s https://api.nuget.org/v3/index.json -k "${{ env.NUGET_KEY }}" + dotnet nuget push "${nuget_path}" --skip-duplicate -s https://api.nuget.org/v3/index.json -k "${{ steps.nuget-login.outputs.NUGET_API_KEY }}" fi done <<< "${{ inputs.nuget-path }}" diff --git a/.github/workflows/_update-packagejson.yaml b/.github/workflows/_update-packagejson.yaml index c461c9bed..6b64f8e1b 100644 --- a/.github/workflows/_update-packagejson.yaml +++ b/.github/workflows/_update-packagejson.yaml @@ -71,7 +71,7 @@ jobs: run: | echo "branch-name=test-release/${{ inputs.tag }}" | tee -a "$GITHUB_OUTPUT" - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 # package.json # "version": 1.2.3 -> "version": 2.0.0 diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 444bdae1a..b73370cf9 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -15,6 +15,7 @@ on: permissions: actions: write contents: write + id-token: write jobs: # for unity. need update package.json from tag @@ -34,7 +35,7 @@ jobs: timeout-minutes: 10 steps: - run: echo ${{ needs.update-packagejson.outputs.sha }} - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: ref: ${{ needs.update-packagejson.outputs.sha }} fetch-depth: 0 @@ -44,7 +45,7 @@ jobs: - run: dotnet test -c Release --no-build - run: dotnet pack -c Release -p:Version=${{ needs.update-packagejson.outputs.normalized_tag }} -o ./publish - name: upload artifacts - uses: actions/upload-artifact@v4 # must sync with actions/download-artifact@v4 in create-release + uses: actions/upload-artifact@v7 # must sync with actions/download-artifact@v8 in create-release with: name: nuget path: ./publish/ diff --git a/.gitignore b/.gitignore index 6ef3a7ca5..7209c6cbc 100644 --- a/.gitignore +++ b/.gitignore @@ -371,3 +371,5 @@ src/MessagePack.UnityClient/Assets/Packages/ BenchmarkDotNet.Artifacts/ src/MessagePack.UnityClient/.vsconfig + +*.lscache diff --git a/LICENSE b/LICENSE index eebeb87e0..c4bc51dae 100644 --- a/LICENSE +++ b/LICENSE @@ -39,3 +39,21 @@ Redistributions of source code must retain the above copyright notice, this list Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +--- + +BufferWriter.cs + +Copyright 2019 .NET Foundation + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/SECURITY.md b/SECURITY.md index aedee6a15..e2612cff1 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -12,6 +12,12 @@ Each supported major version is only serviced for security issues at its tip. For example 2.5 will receive updates but 2.4 will not. 3.0 will receive updates until 3.1 is stable, at which point 3.0 will no longer received security updates. +## Strong-name key + +This repository intentionally includes `opensource.snk`, the strong-name key used to provide stable assembly identity for open-source builds. This key is public by design and is not a credential or package-authenticity secret. + +Do not rely on strong names as a security boundary or as proof that a package was published by the project maintainers. Consume packages from trusted package sources and use the normal NuGet and release provenance checks for package authenticity. + ## Reporting a Vulnerability Please use [the Security tab](https://github.com/MessagePack-CSharp/MessagePack-CSharp/security) to responsibly report security vulnerabilities. diff --git a/global.json b/global.json index 088f23e11..723fc16cb 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "9.0.100", + "version": "10.0.300", "rollForward": "patch", "allowPrerelease": false } diff --git a/sandbox/Sandbox/Program.cs b/sandbox/Sandbox/Program.cs index d787a3247..f8f3ad819 100644 --- a/sandbox/Sandbox/Program.cs +++ b/sandbox/Sandbox/Program.cs @@ -26,7 +26,8 @@ //} -public class ClassA where T : ClassA.ClassB +public class ClassA + where T : ClassA.ClassB { public class ClassB { diff --git a/src/MessagePack.SourceGenerator/CodeAnalysis/GenericTypeParameterInfo.cs b/src/MessagePack.SourceGenerator/CodeAnalysis/GenericTypeParameterInfo.cs index c35fe171a..959df2db8 100644 --- a/src/MessagePack.SourceGenerator/CodeAnalysis/GenericTypeParameterInfo.cs +++ b/src/MessagePack.SourceGenerator/CodeAnalysis/GenericTypeParameterInfo.cs @@ -1,4 +1,4 @@ -// Copyright (c) All contributors. All rights reserved. +// Copyright (c) All contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Immutable; @@ -88,4 +88,8 @@ void AddIf(bool condition, string constraint) return builder.ToString(); } + + public virtual bool Equals(GenericTypeParameterInfo? other) => other is not null && this.Name == other.Name; + + public override int GetHashCode() => StringComparer.Ordinal.GetHashCode(this.Name); } diff --git a/src/MessagePack.SourceGenerator/MessagePack.SourceGenerator.csproj b/src/MessagePack.SourceGenerator/MessagePack.SourceGenerator.csproj index e3c4c5e90..5c73a4db2 100644 --- a/src/MessagePack.SourceGenerator/MessagePack.SourceGenerator.csproj +++ b/src/MessagePack.SourceGenerator/MessagePack.SourceGenerator.csproj @@ -9,6 +9,7 @@ embedded false true + $(NoWarn);RS2007 diff --git a/src/MessagePack.SourceGenerator/Transforms/UnionTemplate.cs b/src/MessagePack.SourceGenerator/Transforms/UnionTemplate.cs index 12ce6a290..08e2ed04a 100644 --- a/src/MessagePack.SourceGenerator/Transforms/UnionTemplate.cs +++ b/src/MessagePack.SourceGenerator/Transforms/UnionTemplate.cs @@ -71,7 +71,7 @@ public virtual string TransformText() if (value != null && this.typeToKeyAndJumpMap.TryGetValue(value.GetType().TypeHandle, out keyValuePair)) { writer.WriteArrayHeader(2); - writer.WriteInt32(keyValuePair.Key); + writer.Write(keyValuePair.Key); switch (keyValuePair.Value) { "); diff --git a/src/MessagePack.SourceGenerator/Transforms/UnionTemplate.tt b/src/MessagePack.SourceGenerator/Transforms/UnionTemplate.tt index 67b78a537..359e165e7 100644 --- a/src/MessagePack.SourceGenerator/Transforms/UnionTemplate.tt +++ b/src/MessagePack.SourceGenerator/Transforms/UnionTemplate.tt @@ -34,7 +34,7 @@ using MsgPack = global::MessagePack; if (value != null && this.typeToKeyAndJumpMap.TryGetValue(value.GetType().TypeHandle, out keyValuePair)) { writer.WriteArrayHeader(2); - writer.WriteInt32(keyValuePair.Key); + writer.Write(keyValuePair.Key); switch (keyValuePair.Value) { <# for(var i = 0; i < Info.SubTypes.Length; i++) { var item = Info.SubTypes[i]; #> diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/package.json b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/package.json index 097e1d562..23ec4fe5f 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/package.json +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/package.json @@ -1,7 +1,7 @@ { "name": "com.github.messagepack-csharp", "displayName": "MessagePack", - "version": "3.1.4", + "version": "3.1.5", "unity": "2021.3", "description": "Extremely Fast MessagePack Serializer for C#.", "keywords": [ diff --git a/src/MessagePack/BufferWriter.cs b/src/MessagePack/BufferWriter.cs index 90ee06e3e..b2ca60937 100644 --- a/src/MessagePack/BufferWriter.cs +++ b/src/MessagePack/BufferWriter.cs @@ -2,7 +2,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) Andrew Arnott. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. using System; using System.Buffers; diff --git a/src/MessagePack/Formatters/DictionaryFormatter.cs b/src/MessagePack/Formatters/DictionaryFormatter.cs index af4d367c5..32ebc2c6b 100644 --- a/src/MessagePack/Formatters/DictionaryFormatter.cs +++ b/src/MessagePack/Formatters/DictionaryFormatter.cs @@ -53,8 +53,7 @@ public void Serialize(ref MessagePackWriter writer, TDictionary? value, MessageP writer.WriteMapHeader(count); - TEnumerator e = this.GetSourceEnumerator(value); - try + using (TEnumerator e = this.GetSourceEnumerator(value)) { while (e.MoveNext()) { @@ -64,10 +63,6 @@ public void Serialize(ref MessagePackWriter writer, TDictionary? value, MessageP valueFormatter.Serialize(ref writer, item.Value, options); } } - finally - { - e.Dispose(); - } } } diff --git a/src/MessagePack/Formatters/DynamicObjectTypeFallbackFormatter.cs b/src/MessagePack/Formatters/DynamicObjectTypeFallbackFormatter.cs index 2c43fa7d2..884d391dd 100644 --- a/src/MessagePack/Formatters/DynamicObjectTypeFallbackFormatter.cs +++ b/src/MessagePack/Formatters/DynamicObjectTypeFallbackFormatter.cs @@ -33,7 +33,6 @@ public void Serialize(ref MessagePackWriter writer, object? value, MessagePackSe } Type type = value.GetType(); - TypeInfo ti = type.GetTypeInfo(); if (type == typeof(object)) { @@ -42,7 +41,7 @@ public void Serialize(ref MessagePackWriter writer, object? value, MessagePackSe return; } - if (PrimitiveObjectFormatter.IsSupportedType(type, ti, value)) + if (PrimitiveObjectFormatter.IsSupportedType(type, value)) { if (!(value is System.Collections.IDictionary || value is System.Collections.ICollection)) { @@ -70,7 +69,7 @@ public void Serialize(ref MessagePackWriter writer, object? value, MessagePackSe Expression.Convert(param0, formatterType), serializeMethodInfo, param1, - ti.IsValueType ? Expression.Unbox(param2, type) : Expression.Convert(param2, type), + type.IsValueType ? Expression.Unbox(param2, type) : Expression.Convert(param2, type), param3); serializerDelegate = Expression.Lambda(body, param0, param1, param2, param3).Compile(); diff --git a/src/MessagePack/Formatters/EnumAsStringFormatter`1.cs b/src/MessagePack/Formatters/EnumAsStringFormatter`1.cs index e3b81fd54..5458dbda4 100644 --- a/src/MessagePack/Formatters/EnumAsStringFormatter`1.cs +++ b/src/MessagePack/Formatters/EnumAsStringFormatter`1.cs @@ -39,8 +39,10 @@ public EnumAsStringFormatter(bool ignoreCase) this.ignoreCase = ignoreCase; StringComparer stringComparer = ignoreCase ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal; - this.isFlags = typeof(T).GetCustomAttribute() is object; - var fields = typeof(T).GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Static); + var type = typeof(T); + + this.isFlags = type.GetCustomAttribute() is object; + var fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Static); var nameValueMapping = new Dictionary(fields.Length, ignoreCase ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal); var valueNameMapping = new Dictionary(); Dictionary? clrToSerializationName = null; diff --git a/src/MessagePack/Formatters/PrimitiveObjectFormatter.cs b/src/MessagePack/Formatters/PrimitiveObjectFormatter.cs index 0e3230e0d..ced58432c 100644 --- a/src/MessagePack/Formatters/PrimitiveObjectFormatter.cs +++ b/src/MessagePack/Formatters/PrimitiveObjectFormatter.cs @@ -37,7 +37,13 @@ protected PrimitiveObjectFormatter() { } + [Obsolete("Please, use the method overload without TypeInfo")] public static bool IsSupportedType(Type type, TypeInfo typeInfo, object value) + { + return IsSupportedType(type, value); + } + + public static bool IsSupportedType(Type type, object value) { if (value == null) { @@ -49,7 +55,7 @@ public static bool IsSupportedType(Type type, TypeInfo typeInfo, object value) return true; } - if (typeInfo.IsEnum) + if (type.IsEnum) { return true; } @@ -133,7 +139,7 @@ public void Serialize(ref MessagePackWriter writer, object? value, MessagePackSe } else { - if (t.GetTypeInfo().IsEnum) + if (t.IsEnum) { Type underlyingType = Enum.GetUnderlyingType(t); var code2 = TypeToJumpCode[underlyingType]; diff --git a/src/MessagePack/Formatters/StandardClassLibraryFormatter.cs b/src/MessagePack/Formatters/StandardClassLibraryFormatter.cs index 51ce1f8c1..71a64908f 100644 --- a/src/MessagePack/Formatters/StandardClassLibraryFormatter.cs +++ b/src/MessagePack/Formatters/StandardClassLibraryFormatter.cs @@ -257,6 +257,9 @@ private DateTimeOffsetFormatter() public void Serialize(ref MessagePackWriter writer, DateTimeOffset value, MessagePackSerializerOptions options) { writer.WriteArrayHeader(2); + + // We're writing a *local* DateTime value in msgpack encoding as if it were UTC time. + // That's incorrect msgpack encoding, but fixing it now would compromise backward compatibility. writer.Write(new DateTime(value.Ticks, DateTimeKind.Utc)); // current ticks as is writer.Write((short)value.Offset.TotalMinutes); // offset is normalized in minutes return; diff --git a/src/MessagePack/Formatters/TypelessFormatter.cs b/src/MessagePack/Formatters/TypelessFormatter.cs index 9e63ca447..a051be19d 100644 --- a/src/MessagePack/Formatters/TypelessFormatter.cs +++ b/src/MessagePack/Formatters/TypelessFormatter.cs @@ -147,8 +147,7 @@ public void Serialize(ref MessagePackWriter writer, object? value, MessagePackSe var typeNameCache = options.OmitAssemblyVersion ? ShortenedTypeNameCache : FullTypeNameCache; if (!typeNameCache.TryGetValue(type, out byte[]? typeName)) { - TypeInfo ti = type.GetTypeInfo(); - if (ti.IsAnonymous() || UseBuiltinTypes.Contains(type)) + if (type.IsAnonymous() || UseBuiltinTypes.Contains(type)) { typeName = null; } @@ -176,8 +175,6 @@ public void Serialize(ref MessagePackWriter writer, object? value, MessagePackSe { if (!Serializers.TryGetValue(type, out serializeMethod)) { - TypeInfo ti = type.GetTypeInfo(); - Type formatterType = typeof(IMessagePackFormatter<>).MakeGenericType(type); ParameterExpression param0 = Expression.Parameter(typeof(object), "formatter"); ParameterExpression param1 = Expression.Parameter(typeof(MessagePackWriter).MakeByRefType(), "writer"); @@ -190,7 +187,7 @@ public void Serialize(ref MessagePackWriter writer, object? value, MessagePackSe Expression.Convert(param0, formatterType), serializeMethodInfo, param1, - ti.IsValueType ? Expression.Unbox(param2, type) : Expression.Convert(param2, type), + type.IsValueType ? Expression.Unbox(param2, type) : Expression.Convert(param2, type), param3); serializeMethod = Expression.Lambda(body, param0, param1, param2, param3).Compile(); @@ -305,8 +302,6 @@ private object DeserializeByTypeName(ArraySegment typeName, ref MessagePac { if (!Deserializers.TryGetValue(type, out deserializeMethod)) { - TypeInfo ti = type.GetTypeInfo(); - Type formatterType = typeof(IMessagePackFormatter<>).MakeGenericType(type); ParameterExpression param0 = Expression.Parameter(typeof(object), "formatter"); ParameterExpression param1 = Expression.Parameter(typeof(MessagePackReader).MakeByRefType(), "reader"); @@ -321,7 +316,7 @@ private object DeserializeByTypeName(ArraySegment typeName, ref MessagePac param2); Expression body = deserialize; - if (ti.IsValueType) + if (type.IsValueType) { body = Expression.Convert(deserialize, typeof(object)); } diff --git a/src/MessagePack/Formatters/UnsafeBinaryFormatters.cs b/src/MessagePack/Formatters/UnsafeBinaryFormatters.cs index 19147191c..df4a7c136 100644 --- a/src/MessagePack/Formatters/UnsafeBinaryFormatters.cs +++ b/src/MessagePack/Formatters/UnsafeBinaryFormatters.cs @@ -66,7 +66,7 @@ private NativeDecimalFormatter() { } - /* decimal underlying "flags, hi, lo, mid" fields are sequential and same layuout with .NET Framework and Mono(Unity) + /* decimal underlying "flags, hi, lo, mid" fields are sequential and same layout with .NET Framework and Mono(Unity) * But target machines must be same endian so restrict only for little endian. */ public unsafe void Serialize(ref MessagePackWriter writer, Decimal value, MessagePackSerializerOptions options) diff --git a/src/MessagePack/Internal/DynamicAssemblyFactory.cs b/src/MessagePack/Internal/DynamicAssemblyFactory.cs index e0804c69f..ea5c9d578 100644 --- a/src/MessagePack/Internal/DynamicAssemblyFactory.cs +++ b/src/MessagePack/Internal/DynamicAssemblyFactory.cs @@ -54,7 +54,7 @@ public DynamicAssemblyFactory(string moduleName) { ImmutableHashSet.Builder skipVisibilityAssemblies = this.lastCreatedDynamicAssemblySkipVisibilityChecks.ToBuilder(); int originalCount = skipVisibilityAssemblies.Count; - SkipClrVisibilityChecks.GetSkipVisibilityChecksRequirements(type.GetTypeInfo(), skipVisibilityAssemblies); + SkipClrVisibilityChecks.GetSkipVisibilityChecksRequirements(type, skipVisibilityAssemblies); lock (this) { diff --git a/src/MessagePack/Internal/ILGeneratorExtensions.cs b/src/MessagePack/Internal/ILGeneratorExtensions.cs index 43a969da9..ff088b895 100644 --- a/src/MessagePack/Internal/ILGeneratorExtensions.cs +++ b/src/MessagePack/Internal/ILGeneratorExtensions.cs @@ -27,8 +27,7 @@ public ArgumentField(ILGenerator il, int i, Type type) { this.il = il; this.i = i; - TypeInfo ti = type.GetTypeInfo(); - this.@ref = (ti.IsClass || ti.IsInterface || ti.IsAbstract) ? false : true; + this.@ref = (type.IsClass || type.IsInterface || type.IsAbstract) ? false : true; } public void EmitLoad() @@ -228,7 +227,7 @@ public static void EmitLdc_I4(this ILGenerator il, int value) public static void EmitUnboxOrCast(this ILGenerator il, Type type) { - if (type.GetTypeInfo().IsValueType) + if (type.IsValueType) { il.Emit(OpCodes.Unbox_Any, type); } @@ -240,7 +239,7 @@ public static void EmitUnboxOrCast(this ILGenerator il, Type type) public static void EmitBoxOrDoNothing(this ILGenerator il, Type type) { - if (type.GetTypeInfo().IsValueType) + if (type.IsValueType) { il.Emit(OpCodes.Box, type); } @@ -362,7 +361,8 @@ public static void EmitULong(this ILGenerator il, ulong value) public static void EmitThrowNotimplemented(this ILGenerator il) { - il.Emit(OpCodes.Newobj, typeof(System.NotImplementedException).GetTypeInfo().DeclaredConstructors.First(x => x.GetParameters().Length == 0)); + il.Emit(OpCodes.Newobj, typeof(System.NotImplementedException).GetConstructors() + .First(x => x.GetParameters().Length == 0)); il.Emit(OpCodes.Throw); } diff --git a/src/MessagePack/Internal/ReflectionExtensions.cs b/src/MessagePack/Internal/ReflectionExtensions.cs index 52eea0735..001fc9158 100644 --- a/src/MessagePack/Internal/ReflectionExtensions.cs +++ b/src/MessagePack/Internal/ReflectionExtensions.cs @@ -2,25 +2,18 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.Linq; -using System.Reflection; using System.Runtime.CompilerServices; namespace MessagePack.Internal { internal static class ReflectionExtensions { - public static bool IsNullable(this System.Reflection.TypeInfo type) + public static bool IsNullable(this Type type) { return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(System.Nullable<>); } - public static bool IsPublic(this System.Reflection.TypeInfo type) - { - return type.IsPublic; - } - - public static bool IsAnonymous(this System.Reflection.TypeInfo type) + public static bool IsAnonymous(this Type type) { return type.Namespace == null && type.IsSealed @@ -34,26 +27,5 @@ public static bool IsIndexer(this System.Reflection.PropertyInfo propertyInfo) { return propertyInfo.GetIndexParameters().Length > 0; } - - public static bool IsConstructedGenericType(this System.Reflection.TypeInfo type) - { - return type.AsType().IsConstructedGenericType; - } - - public static MethodInfo? GetGetMethod(this PropertyInfo propInfo) - { - return propInfo.GetMethod; - } - - public static MethodInfo? GetSetMethod(this PropertyInfo propInfo) - { - return propInfo.SetMethod; - } - - public static bool HasPrivateCtorForSerialization(this TypeInfo type) - { - var markedCtor = type.DeclaredConstructors.SingleOrDefault(x => x.GetCustomAttribute(false) != null); - return markedCtor?.Attributes.HasFlag(MethodAttributes.Private) ?? false; - } } } diff --git a/src/MessagePack/Internal/Sequence`1.cs b/src/MessagePack/Internal/Sequence`1.cs index 9d4ff862c..72a445541 100644 --- a/src/MessagePack/Internal/Sequence`1.cs +++ b/src/MessagePack/Internal/Sequence`1.cs @@ -28,7 +28,7 @@ namespace Nerdbank.Streams // NOTE: invalid namespace, should modify /// Instance members are not thread-safe. /// [DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")] - internal class Sequence : IBufferWriter, IDisposable + internal sealed class Sequence : IBufferWriter, IDisposable { private const int MaximumAutoGrowSize = 32 * 1024; @@ -361,7 +361,7 @@ private class SequenceSegment : ReadOnlySequenceSegment /// /// A value indicating whether the element may contain references (and thus must be cleared). /// - private static readonly bool MayContainReferences = !typeof(T).GetTypeInfo().IsPrimitive; + private static readonly bool MayContainReferences = !typeof(T).IsPrimitive; #pragma warning disable SA1011 // Closing square brackets should be spaced correctly /// diff --git a/src/MessagePack/Internal/TinyJsonReader.cs b/src/MessagePack/Internal/TinyJsonReader.cs index e4ceaabfe..dd386177c 100644 --- a/src/MessagePack/Internal/TinyJsonReader.cs +++ b/src/MessagePack/Internal/TinyJsonReader.cs @@ -58,7 +58,7 @@ protected TinyJsonException(SerializationInfo info, StreamingContext context) } } - internal class TinyJsonReader : IDisposable + internal sealed class TinyJsonReader : IDisposable { private readonly TextReader reader; private readonly bool disposeInnerReader; diff --git a/src/MessagePack/MessagePackSecurity.cs b/src/MessagePack/MessagePackSecurity.cs index 2e59d957f..7b3fe62b0 100644 --- a/src/MessagePack/MessagePackSecurity.cs +++ b/src/MessagePack/MessagePackSecurity.cs @@ -153,30 +153,32 @@ private class HashResistantCache static HashResistantCache() { + var type = typeof(T); + // We have to specially handle some 32-bit types (e.g. float) where multiple in-memory representations should hash to the same value. // Any type supported by the PrimitiveObjectFormatter should be added here if supporting it as a key in a collection makes sense. EqualityComparer = - typeof(T) == typeof(bool) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : - typeof(T) == typeof(char) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : - typeof(T) == typeof(sbyte) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : - typeof(T) == typeof(byte) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : - typeof(T) == typeof(short) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : - typeof(T) == typeof(ushort) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : - typeof(T) == typeof(int) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : - typeof(T) == typeof(uint) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : - typeof(T) == typeof(long) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : - typeof(T) == typeof(ulong) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : - typeof(T) == typeof(Guid) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : + type == typeof(bool) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : + type == typeof(char) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : + type == typeof(sbyte) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : + type == typeof(byte) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : + type == typeof(short) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : + type == typeof(ushort) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : + type == typeof(int) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : + type == typeof(uint) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : + type == typeof(long) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : + type == typeof(ulong) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : + type == typeof(Guid) ? (IEqualityComparer)CollisionResistantHasherUnmanaged.Instance : // Data types that are managed or have multiple in-memory representations for equivalent values: - typeof(T) == typeof(float) ? (IEqualityComparer)SingleEqualityComparer.Instance : - typeof(T) == typeof(double) ? (IEqualityComparer)DoubleEqualityComparer.Instance : - typeof(T) == typeof(string) ? (IEqualityComparer)StringEqualityComparer.Instance : - typeof(T) == typeof(DateTime) ? (IEqualityComparer)DateTimeEqualityComparer.Instance : - typeof(T) == typeof(DateTimeOffset) ? (IEqualityComparer)DateTimeOffsetEqualityComparer.Instance : + type == typeof(float) ? (IEqualityComparer)SingleEqualityComparer.Instance : + type == typeof(double) ? (IEqualityComparer)DoubleEqualityComparer.Instance : + type == typeof(string) ? (IEqualityComparer)StringEqualityComparer.Instance : + type == typeof(DateTime) ? (IEqualityComparer)DateTimeEqualityComparer.Instance : + type == typeof(DateTimeOffset) ? (IEqualityComparer)DateTimeOffsetEqualityComparer.Instance : // Call out each primitive behind an enum explicitly to avoid dynamically generating code. - typeof(T).GetTypeInfo().IsEnum && typeof(T).GetTypeInfo().GetEnumUnderlyingType() is Type underlying ? ( + type.IsEnum && type.GetEnumUnderlyingType() is Type underlying ? ( underlying == typeof(byte) ? CollisionResistantEnumHasher.Instance : underlying == typeof(sbyte) ? CollisionResistantEnumHasher.Instance : underlying == typeof(ushort) ? CollisionResistantEnumHasher.Instance : diff --git a/src/MessagePack/MessagePackSerializer.Json.cs b/src/MessagePack/MessagePackSerializer.Json.cs index 1dfdf49db..ebcddd555 100644 --- a/src/MessagePack/MessagePackSerializer.Json.cs +++ b/src/MessagePack/MessagePackSerializer.Json.cs @@ -44,9 +44,11 @@ public static void SerializeToJson(TextWriter textWriter, T obj, MessagePackS /// Thrown if an error occurs during serialization. public static string SerializeToJson(T obj, MessagePackSerializerOptions? options = null, CancellationToken cancellationToken = default) { - var writer = new StringWriter(); - SerializeToJson(writer, obj, options, cancellationToken); - return writer.ToString(); + using (var writer = new StringWriter()) + { + SerializeToJson(writer, obj, options, cancellationToken); + return writer.ToString(); + } } /// @@ -61,13 +63,15 @@ public static string SerializeToJson(T obj, MessagePackSerializerOptions? opt /// Thrown if an error occurs while reading the messagepack data or writing out the JSON. public static string ConvertToJson(in ReadOnlySequence bytes, MessagePackSerializerOptions? options = null, CancellationToken cancellationToken = default) { - var jsonWriter = new StringWriter(); - var reader = new MessagePackReader(bytes) + using (var jsonWriter = new StringWriter()) { - CancellationToken = cancellationToken, - }; - ConvertToJson(ref reader, jsonWriter, options); - return jsonWriter.ToString(); + var reader = new MessagePackReader(bytes) + { + CancellationToken = cancellationToken, + }; + ConvertToJson(ref reader, jsonWriter, options); + return jsonWriter.ToString(); + } } /// diff --git a/src/MessagePack/MessagePackSerializer.NonGeneric.cs b/src/MessagePack/MessagePackSerializer.NonGeneric.cs index 1495e4e65..b86c4c862 100644 --- a/src/MessagePack/MessagePackSerializer.NonGeneric.cs +++ b/src/MessagePack/MessagePackSerializer.NonGeneric.cs @@ -134,7 +134,6 @@ private class CompiledMethods internal CompiledMethods(Type type) { - TypeInfo ti = type.GetTypeInfo(); { // public static byte[] Serialize(T obj, MessagePackSerializerOptions options, CancellationToken cancellationToken) MethodInfo serialize = GetMethod(nameof(Serialize), type, new Type?[] { null, typeof(MessagePackSerializerOptions), typeof(CancellationToken) }); @@ -151,7 +150,7 @@ internal CompiledMethods(Type type) MethodCallExpression body = Expression.Call( null, serialize, - ti.IsValueType ? Expression.Unbox(param1, type) : Expression.Convert(param1, type), + type.IsValueType ? Expression.Unbox(param1, type) : Expression.Convert(param1, type), param2, param3); Func lambda = Expression.Lambda>(body, param1, param2, param3).Compile(PreferInterpretation); @@ -178,7 +177,7 @@ internal CompiledMethods(Type type) null, serialize, param1, - ti.IsValueType ? Expression.Unbox(param2, type) : Expression.Convert(param2, type), + type.IsValueType ? Expression.Unbox(param2, type) : Expression.Convert(param2, type), param3, param4); Action lambda = Expression.Lambda>(body, param1, param2, param3, param4).Compile(PreferInterpretation); @@ -205,7 +204,7 @@ internal CompiledMethods(Type type) null, serialize, param1, - ti.IsValueType ? Expression.Unbox(param2, type) : Expression.Convert(param2, type), + type.IsValueType ? Expression.Unbox(param2, type) : Expression.Convert(param2, type), param3, param4); Func lambda = Expression.Lambda>(body, param1, param2, param3, param4).Compile(PreferInterpretation); @@ -232,7 +231,7 @@ internal CompiledMethods(Type type) null, serialize, param1, - ti.IsValueType ? Expression.Unbox(param2, type) : Expression.Convert(param2, type), + type.IsValueType ? Expression.Unbox(param2, type) : Expression.Convert(param2, type), param3, param4); Action, object?, MessagePackSerializerOptions?, CancellationToken> lambda = Expression.Lambda, object?, MessagePackSerializerOptions?, CancellationToken>>(body, param1, param2, param3, param4).Compile(PreferInterpretation); diff --git a/src/MessagePack/MessagePackSerializerOptions.cs b/src/MessagePack/MessagePackSerializerOptions.cs index f750f93df..dc4598239 100644 --- a/src/MessagePack/MessagePackSerializerOptions.cs +++ b/src/MessagePack/MessagePackSerializerOptions.cs @@ -25,7 +25,13 @@ public class MessagePackSerializerOptions private static readonly HashSet DisallowedTypes = new HashSet { "System.CodeDom.Compiler.TempFileCollection", + "System.IdentityModel.Tokens.SessionSecurityToken", "System.Management.IWbemClassObjectFreeThreaded", + "System.Security.Claims.ClaimsIdentity", + "System.Security.Principal.WindowsIdentity", + "System.Web.Security.RolePrincipal", + "System.Windows.Data.ObjectDataProvider", + "System.Windows.ResourceDictionary", }; #if !DYNAMICCODEDUMPER diff --git a/src/MessagePack/Resolvers/AttributeFormatterResolver.cs b/src/MessagePack/Resolvers/AttributeFormatterResolver.cs index eec41fc92..e420661ac 100644 --- a/src/MessagePack/Resolvers/AttributeFormatterResolver.cs +++ b/src/MessagePack/Resolvers/AttributeFormatterResolver.cs @@ -33,7 +33,7 @@ private static class FormatterCache static FormatterCache() { - MessagePackFormatterAttribute? attr = typeof(T).GetTypeInfo().GetCustomAttribute(); + MessagePackFormatterAttribute? attr = typeof(T).GetCustomAttribute(); if (attr == null) { return; diff --git a/src/MessagePack/Resolvers/DynamicEnumAsStringIgnoreCaseResolver.cs b/src/MessagePack/Resolvers/DynamicEnumAsStringIgnoreCaseResolver.cs index afa565d02..2a7f723c2 100644 --- a/src/MessagePack/Resolvers/DynamicEnumAsStringIgnoreCaseResolver.cs +++ b/src/MessagePack/Resolvers/DynamicEnumAsStringIgnoreCaseResolver.cs @@ -32,27 +32,27 @@ private static class FormatterCache static FormatterCache() { - TypeInfo ti = typeof(T).GetTypeInfo(); + Type type = typeof(T); - if (ti.IsNullable()) + if (type.IsNullable()) { // build underlying type and use wrapped formatter. - ti = ti.GenericTypeArguments[0].GetTypeInfo(); - if (!ti.IsEnum) + type = type.GenericTypeArguments[0]; + if (!type.IsEnum) { return; } - var innerFormatter = Instance.GetFormatterDynamic(ti.AsType()); + var innerFormatter = Instance.GetFormatterDynamic(type); if (innerFormatter == null) { return; } - Formatter = (IMessagePackFormatter?)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(ti.AsType()), new object[] { innerFormatter }); + Formatter = (IMessagePackFormatter?)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(type), new object[] { innerFormatter }); return; } - else if (!ti.IsEnum) + else if (!type.IsEnum) { return; } diff --git a/src/MessagePack/Resolvers/DynamicEnumAsStringResolver.cs b/src/MessagePack/Resolvers/DynamicEnumAsStringResolver.cs index b8610fa3c..d2de589e2 100644 --- a/src/MessagePack/Resolvers/DynamicEnumAsStringResolver.cs +++ b/src/MessagePack/Resolvers/DynamicEnumAsStringResolver.cs @@ -41,27 +41,27 @@ private static class FormatterCache static FormatterCache() { - TypeInfo ti = typeof(T).GetTypeInfo(); + Type type = typeof(T); - if (ti.IsNullable()) + if (type.IsNullable()) { // build underlying type and use wrapped formatter. - ti = ti.GenericTypeArguments[0].GetTypeInfo(); - if (!ti.IsEnum) + type = type.GenericTypeArguments[0]; + if (!type.IsEnum) { return; } - var innerFormatter = DynamicEnumAsStringResolver.Instance.GetFormatterDynamic(ti.AsType()); + var innerFormatter = DynamicEnumAsStringResolver.Instance.GetFormatterDynamic(type); if (innerFormatter == null) { return; } - Formatter = (IMessagePackFormatter?)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(ti.AsType()), new object[] { innerFormatter }); + Formatter = (IMessagePackFormatter?)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(type), new object[] { innerFormatter }); return; } - else if (!ti.IsEnum) + else if (!type.IsEnum) { return; } diff --git a/src/MessagePack/Resolvers/DynamicEnumResolver.cs b/src/MessagePack/Resolvers/DynamicEnumResolver.cs index c05769f1b..e993f4af0 100644 --- a/src/MessagePack/Resolvers/DynamicEnumResolver.cs +++ b/src/MessagePack/Resolvers/DynamicEnumResolver.cs @@ -54,32 +54,32 @@ private static class FormatterCache static FormatterCache() { - TypeInfo ti = typeof(T).GetTypeInfo(); - if (ti.IsNullable()) + Type type = typeof(T); + if (type.IsNullable()) { // build underlying type and use wrapped formatter. - ti = ti.GenericTypeArguments[0].GetTypeInfo(); - if (!ti.IsEnum) + type = type.GenericTypeArguments[0]; + if (!type.IsEnum) { return; } - var innerFormatter = DynamicEnumResolver.Instance.GetFormatterDynamic(ti.AsType()); + var innerFormatter = DynamicEnumResolver.Instance.GetFormatterDynamic(type); if (innerFormatter == null) { return; } - Formatter = (IMessagePackFormatter?)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(ti.AsType()), new object[] { innerFormatter }); + Formatter = (IMessagePackFormatter?)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(type), new object[] { innerFormatter }); return; } - else if (!ti.IsEnum) + else if (!type.IsEnum) { return; } - TypeInfo formatterTypeInfo = BuildType(typeof(T), allowPrivate: false); - Formatter = (IMessagePackFormatter?)Activator.CreateInstance(formatterTypeInfo.AsType()); + TypeInfo formatterTypeInfo = BuildType(type, allowPrivate: false); + Formatter = (IMessagePackFormatter?)Activator.CreateInstance(formatterTypeInfo); } } diff --git a/src/MessagePack/Resolvers/DynamicGenericResolver.cs b/src/MessagePack/Resolvers/DynamicGenericResolver.cs index cb1a2248a..31a5a73fe 100644 --- a/src/MessagePack/Resolvers/DynamicGenericResolver.cs +++ b/src/MessagePack/Resolvers/DynamicGenericResolver.cs @@ -93,8 +93,6 @@ internal static class DynamicGenericResolverGetFormatterHelper // Reduce IL2CPP code generate size(don't write long code in ) internal static object? GetFormatter(Type t) { - TypeInfo ti = t.GetTypeInfo(); - if (t.IsArray) { var rank = t.GetArrayRank(); @@ -125,23 +123,22 @@ internal static class DynamicGenericResolverGetFormatterHelper return null; // not supported built-in } } - else if (ti.IsGenericType) + else if (t.IsGenericType) { - Type genericType = ti.GetGenericTypeDefinition(); - TypeInfo genericTypeInfo = genericType.GetTypeInfo(); - var isNullable = genericTypeInfo.IsNullable(); - Type? nullableElementType = isNullable ? ti.GenericTypeArguments[0] : null; + Type genericType = t.GetGenericTypeDefinition(); + var isNullable = genericType.IsNullable(); + Type? nullableElementType = isNullable ? t.GenericTypeArguments[0] : null; if (genericType == typeof(KeyValuePair<,>)) { - return CreateInstance(typeof(KeyValuePairFormatter<,>), ti.GenericTypeArguments); + return CreateInstance(typeof(KeyValuePairFormatter<,>), t.GenericTypeArguments); } // Tuple - else if (ti.FullName?.StartsWith("System.Tuple") is true) + else if (t.FullName?.StartsWith("System.Tuple") is true) { Type? tupleFormatterType = null; - switch (ti.GenericTypeArguments.Length) + switch (t.GenericTypeArguments.Length) { case 1: tupleFormatterType = typeof(TupleFormatter<>); @@ -168,17 +165,17 @@ internal static class DynamicGenericResolverGetFormatterHelper tupleFormatterType = typeof(TupleFormatter<,,,,,,,>); break; default: - throw new MessagePackSerializationException("Unsupported arity for Tuple generic type: " + ti.Name); + throw new MessagePackSerializationException("Unsupported arity for Tuple generic type: " + t.Name); } - return CreateInstance(tupleFormatterType, ti.GenericTypeArguments); + return CreateInstance(tupleFormatterType, t.GenericTypeArguments); } // ValueTuple - else if (ti.FullName?.StartsWith("System.ValueTuple") is true) + else if (t.FullName?.StartsWith("System.ValueTuple") is true) { Type? tupleFormatterType = null; - switch (ti.GenericTypeArguments.Length) + switch (t.GenericTypeArguments.Length) { case 1: tupleFormatterType = typeof(ValueTupleFormatter<>); @@ -205,61 +202,61 @@ internal static class DynamicGenericResolverGetFormatterHelper tupleFormatterType = typeof(ValueTupleFormatter<,,,,,,,>); break; default: - throw new MessagePackSerializationException("Unsupported arity for ValueTuple generic type: " + ti.Name); + throw new MessagePackSerializationException("Unsupported arity for ValueTuple generic type: " + t.Name); } - return CreateInstance(tupleFormatterType, ti.GenericTypeArguments); + return CreateInstance(tupleFormatterType, t.GenericTypeArguments); } // ArraySegment else if (genericType == typeof(ArraySegment<>)) { - if (ti.GenericTypeArguments[0] == typeof(byte)) + if (t.GenericTypeArguments[0] == typeof(byte)) { return ByteArraySegmentFormatter.Instance; } else { - return CreateInstance(typeof(ArraySegmentFormatter<>), ti.GenericTypeArguments); + return CreateInstance(typeof(ArraySegmentFormatter<>), t.GenericTypeArguments); } } // Memory else if (genericType == typeof(Memory<>)) { - if (ti.GenericTypeArguments[0] == typeof(byte)) + if (t.GenericTypeArguments[0] == typeof(byte)) { return ByteMemoryFormatter.Instance; } else { - return CreateInstance(typeof(MemoryFormatter<>), ti.GenericTypeArguments); + return CreateInstance(typeof(MemoryFormatter<>), t.GenericTypeArguments); } } // ReadOnlyMemory else if (genericType == typeof(ReadOnlyMemory<>)) { - if (ti.GenericTypeArguments[0] == typeof(byte)) + if (t.GenericTypeArguments[0] == typeof(byte)) { return ByteReadOnlyMemoryFormatter.Instance; } else { - return CreateInstance(typeof(ReadOnlyMemoryFormatter<>), ti.GenericTypeArguments); + return CreateInstance(typeof(ReadOnlyMemoryFormatter<>), t.GenericTypeArguments); } } // ReadOnlySequence else if (genericType == typeof(ReadOnlySequence<>)) { - if (ti.GenericTypeArguments[0] == typeof(byte)) + if (t.GenericTypeArguments[0] == typeof(byte)) { return ByteReadOnlySequenceFormatter.Instance; } else { - return CreateInstance(typeof(ReadOnlySequenceFormatter<>), ti.GenericTypeArguments); + return CreateInstance(typeof(ReadOnlySequenceFormatter<>), t.GenericTypeArguments); } } @@ -274,11 +271,11 @@ internal static class DynamicGenericResolverGetFormatterHelper { if (FormatterMap.TryGetValue(genericType, out Type? formatterType)) { - return CreateInstance(formatterType, ti.GenericTypeArguments); + return CreateInstance(formatterType, t.GenericTypeArguments); } } } - else if (ti.IsEnum) + else if (t.IsEnum) { return CreateInstance(typeof(GenericEnumFormatter<>), new[] { t }); } @@ -302,11 +299,13 @@ internal static class DynamicGenericResolverGetFormatterHelper return NonGenericInterfaceDictionaryFormatter.Instance; } - if (typeof(IList).GetTypeInfo().IsAssignableFrom(ti) && ti.DeclaredConstructors.Any(x => x.GetParameters().Length == 0)) + if (typeof(IList).IsAssignableFrom(t) && t.GetConstructors(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.NonPublic) + .Any(x => x.GetParameters().Length == 0)) { return Activator.CreateInstance(typeof(NonGenericListFormatter<>).MakeGenericType(t)); } - else if (typeof(IDictionary).GetTypeInfo().IsAssignableFrom(ti) && ti.DeclaredConstructors.Any(x => x.GetParameters().Length == 0)) + else if (typeof(IDictionary).IsAssignableFrom(t) && t.GetConstructors(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.NonPublic) + .Any(x => x.GetParameters().Length == 0)) { return Activator.CreateInstance(typeof(NonGenericDictionaryFormatter<>).MakeGenericType(t)); } @@ -315,8 +314,9 @@ internal static class DynamicGenericResolverGetFormatterHelper // check inherited types(e.g. Foo : ICollection<>, Bar : ICollection) { // generic dictionary - var dictionaryDef = ti.ImplementedInterfaces.FirstOrDefault(x => x.GetTypeInfo().IsConstructedGenericType() && x.GetGenericTypeDefinition() == typeof(IDictionary<,>)); - if (dictionaryDef != null && ti.DeclaredConstructors.Any(x => !x.IsStatic && x.GetParameters().Length == 0)) + var dictionaryDef = t.GetInterfaces().FirstOrDefault(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IDictionary<,>)); + if (dictionaryDef != null && t.GetConstructors(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.NonPublic) + .Any(x => x.GetParameters().Length == 0)) { Type keyType = dictionaryDef.GenericTypeArguments[0]; Type valueType = dictionaryDef.GenericTypeArguments[1]; @@ -324,7 +324,7 @@ internal static class DynamicGenericResolverGetFormatterHelper } // generic dictionary with collection ctor - var dictionaryInterfaceDef = ti.ImplementedInterfaces.FirstOrDefault(x => x.GetTypeInfo().IsConstructedGenericType() && + var dictionaryInterfaceDef = t.GetInterfaces().FirstOrDefault(x => x.IsConstructedGenericType && (x.GetGenericTypeDefinition() == typeof(IReadOnlyDictionary<,>))); if (dictionaryInterfaceDef != null) { @@ -336,7 +336,7 @@ internal static class DynamicGenericResolverGetFormatterHelper typeof(IReadOnlyDictionary<,>).MakeGenericType(keyType, valueType), typeof(IEnumerable<>).MakeGenericType(typeof(KeyValuePair<,>).MakeGenericType(keyType, valueType)), }; - foreach (var constructor in ti.DeclaredConstructors) + foreach (var constructor in t.GetConstructors(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.NonPublic)) { ParameterInfo[] parameters = constructor.GetParameters(); if (parameters.Length == 1 && @@ -348,8 +348,9 @@ internal static class DynamicGenericResolverGetFormatterHelper } // generic collection - var collectionDef = ti.ImplementedInterfaces.FirstOrDefault(x => x.GetTypeInfo().IsConstructedGenericType() && x.GetGenericTypeDefinition() == typeof(ICollection<>)); - if (collectionDef != null && ti.DeclaredConstructors.Any(x => !x.IsStatic && x.GetParameters().Length == 0)) + var collectionDef = t.GetInterfaces().FirstOrDefault(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(ICollection<>)); + if (collectionDef != null && t.GetConstructors(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.NonPublic) + .Any(x => x.GetParameters().Length == 0)) { Type elemType = collectionDef.GenericTypeArguments[0]; return CreateInstance(typeof(GenericCollectionFormatter<,>), new[] { elemType, t }); @@ -358,11 +359,11 @@ internal static class DynamicGenericResolverGetFormatterHelper // generic IEnumerable collection // looking for combination of IEnumerable and constructor that takes // enumeration of the same type - foreach (var enumerableCollectionDef in ti.ImplementedInterfaces.Where(x => x.GetTypeInfo().IsConstructedGenericType() && x.GetGenericTypeDefinition() == typeof(IEnumerable<>))) + foreach (var enumerableCollectionDef in t.GetInterfaces().Where(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable<>))) { Type elemType = enumerableCollectionDef.GenericTypeArguments[0]; Type paramInterface = typeof(IEnumerable<>).MakeGenericType(elemType); - foreach (var constructor in ti.DeclaredConstructors) + foreach (var constructor in t.GetConstructors(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.NonPublic)) { var parameters = constructor.GetParameters(); if (parameters.Length == 1 && parameters[0].ParameterType.IsAssignableFrom(paramInterface)) diff --git a/src/MessagePack/Resolvers/DynamicObjectResolver.cs b/src/MessagePack/Resolvers/DynamicObjectResolver.cs index c3d281337..6eb62e235 100644 --- a/src/MessagePack/Resolvers/DynamicObjectResolver.cs +++ b/src/MessagePack/Resolvers/DynamicObjectResolver.cs @@ -61,15 +61,15 @@ private DynamicObjectResolver() internal static IMessagePackFormatter? BuildFormatterHelper(IFormatterResolver self, DynamicAssemblyFactory dynamicAssemblyFactory, bool forceStringKey, bool contractless, bool allowPrivate) { - TypeInfo ti = typeof(T).GetTypeInfo(); + Type type = typeof(T); - if (ti.IsInterface || ti.IsAbstract) + if (type.IsInterface || type.IsAbstract) { return null; } DynamicAssembly? dynamicAssembly = null; - if (ti.IsAnonymous()) + if (type.IsAnonymous()) { forceStringKey = true; contractless = true; @@ -78,25 +78,25 @@ private DynamicObjectResolver() // but *not* look at non-public members to avoid double-serialization of the properties // as well as their backing fields. allowPrivate = false; - dynamicAssembly = DynamicAssemblyFactory.GetDynamicAssembly(typeof(T), true); + dynamicAssembly = DynamicAssemblyFactory.GetDynamicAssembly(type, true); } - else if (ti.IsNullable()) + else if (type.IsNullable()) { - ti = ti.GenericTypeArguments[0].GetTypeInfo(); + type = type.GenericTypeArguments[0]; - var innerFormatter = self.GetFormatterDynamic(ti.AsType()); + var innerFormatter = self.GetFormatterDynamic(type); if (innerFormatter == null) { return null; } - return (IMessagePackFormatter?)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(ti.AsType()), [innerFormatter]); + return (IMessagePackFormatter?)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(type), [innerFormatter]); } - allowPrivate |= !contractless && typeof(T).GetCustomAttributes().Any(a => a.AllowPrivate); - dynamicAssembly ??= DynamicAssemblyFactory.GetDynamicAssembly(typeof(T), allowPrivate); - TypeInfo? formatterTypeInfo = DynamicObjectTypeBuilder.BuildType(dynamicAssembly, typeof(T), forceStringKey, contractless, allowPrivate); - return formatterTypeInfo is null ? null : (IMessagePackFormatter)ResolverUtilities.ActivateFormatter(formatterTypeInfo.AsType()); + allowPrivate |= !contractless && type.GetCustomAttributes().Any(a => a.AllowPrivate); + dynamicAssembly ??= DynamicAssemblyFactory.GetDynamicAssembly(type, allowPrivate); + TypeInfo? formatterTypeInfo = DynamicObjectTypeBuilder.BuildType(dynamicAssembly, type, forceStringKey, contractless, allowPrivate); + return formatterTypeInfo is null ? null : (IMessagePackFormatter)ResolverUtilities.ActivateFormatter(formatterTypeInfo); } private static class FormatterCache @@ -239,7 +239,7 @@ internal static class DynamicObjectTypeBuilder return null; } - if (!allowPrivate && !(type.IsPublic || type.IsNestedPublic) && !type.GetTypeInfo().IsAnonymous()) + if (!allowPrivate && !(type.IsPublic || type.IsNestedPublic) && !type.IsAnonymous()) { throw new MessagePackSerializationException("Building dynamic formatter only allows public type. Type: " + type.FullName); } @@ -462,7 +462,7 @@ private static void BuildSerialize(Type type, ObjectSerializationInfo info, ILGe var argOptions = new ArgumentField(il, firstArgIndex + 2); // if(value == null) return WriteNil - if (type.GetTypeInfo().IsClass) + if (type.IsClass) { Label elseBody = il.DefineLabel(); @@ -476,7 +476,7 @@ private static void BuildSerialize(Type type, ObjectSerializationInfo info, ILGe } // IMessagePackSerializationCallbackReceiver.OnBeforeSerialize() - if (type.GetTypeInfo().ImplementedInterfaces.Any(x => x == typeof(IMessagePackSerializationCallbackReceiver))) + if (type.GetInterfaces().Any(x => x == typeof(IMessagePackSerializationCallbackReceiver))) { // call directly MethodInfo[] runtimeMethods = type.GetRuntimeMethods().Where(x => x.Name == "OnBeforeSerialize").ToArray(); @@ -515,7 +515,7 @@ private static void BuildSerialize(Type type, ObjectSerializationInfo info, ILGe { if (intKeyMap.TryGetValue(i, out ObjectSerializationInfo.EmittableMember? member)) { - EmitSerializeValue(il, type.GetTypeInfo(), member, index++, tryEmitLoadCustomFormatter, argWriter, argValue, argOptions, localResolver); + EmitSerializeValue(il, member, index++, tryEmitLoadCustomFormatter, argWriter, argValue, argOptions, localResolver); } else { @@ -568,7 +568,7 @@ private static void BuildSerialize(Type type, ObjectSerializationInfo info, ILGe il.EmitCall(MessagePackWriterTypeInfo.WriteRaw); } - EmitSerializeValue(il, type.GetTypeInfo(), item, index, tryEmitLoadCustomFormatter, argWriter, argValue, argOptions, localResolver); + EmitSerializeValue(il, item, index, tryEmitLoadCustomFormatter, argWriter, argValue, argOptions, localResolver); index++; } } @@ -576,7 +576,7 @@ private static void BuildSerialize(Type type, ObjectSerializationInfo info, ILGe il.Emit(OpCodes.Ret); } - private static void EmitSerializeValue(ILGenerator il, TypeInfo type, ObjectSerializationInfo.EmittableMember member, int index, Func tryEmitLoadCustomFormatter, ArgumentField argWriter, ArgumentField argValue, ArgumentField argOptions, LocalBuilder localResolver) + private static void EmitSerializeValue(ILGenerator il, ObjectSerializationInfo.EmittableMember member, int index, Func tryEmitLoadCustomFormatter, ArgumentField argWriter, ArgumentField argValue, ArgumentField argOptions, LocalBuilder localResolver) { Label endLabel = il.DefineLabel(); Type t = member.Type; @@ -592,7 +592,7 @@ private static void EmitSerializeValue(ILGenerator il, TypeInfo type, ObjectSeri } else if (ObjectSerializationInfo.IsOptimizeTargetType(t)) { - if (!t.GetTypeInfo().IsValueType) + if (!t.IsValueType) { // As a nullable type (e.g. byte[] and string) we need to call WriteNil for null values. Label writeNonNilValueLabel = il.DefineLabel(); @@ -1060,7 +1060,7 @@ private static void BuildDeserializeInternalTryReadNil(Type type, ILGenerator il argReader.EmitLdarg(); il.EmitCall(MessagePackReaderTypeInfo.TryReadNil); il.Emit(OpCodes.Brfalse_S, falseLabel); - if (type.GetTypeInfo().IsClass) + if (type.IsClass) { il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Ret); @@ -1087,7 +1087,7 @@ private static void BuildDeserializeInternalDepthUnStep(ILGenerator il, ref Argu private static void BuildDeserializeInternalOnAfterDeserialize(Type type, ObjectSerializationInfo info, ILGenerator il, LocalBuilder localResult) { - if (type.GetTypeInfo().ImplementedInterfaces.All(x => x != typeof(IMessagePackSerializationCallbackReceiver))) + if (type.GetInterfaces().All(x => x != typeof(IMessagePackSerializationCallbackReceiver))) { return; } @@ -1197,7 +1197,7 @@ private static void BuildDeserializeInternalDeserializeValueAssignDirectly(TypeB } else if (ObjectSerializationInfo.IsOptimizeTargetType(t)) { - if (!t.GetTypeInfo().IsValueType) + if (!t.IsValueType) { // As a nullable type (e.g. byte[] and string) we need to first call TryReadNil // if (reader.TryReadNil()) @@ -1267,7 +1267,7 @@ private static void BuildDeserializeInternalDeserializeValueAssignLocalVariable( } else if (ObjectSerializationInfo.IsOptimizeTargetType(t)) { - if (!t.GetTypeInfo().IsValueType) + if (!t.IsValueType) { // As a nullable type (e.g. byte[] and string) we need to first call TryReadNil // if (reader.TryReadNil()) @@ -1383,8 +1383,8 @@ internal static class CodeGenHelpersTypeInfo internal static class EmitInfo { internal static readonly MethodInfo GetTypeFromHandle = ExpressionUtility.GetMethodInfo(() => Type.GetTypeFromHandle(default(RuntimeTypeHandle))); - internal static readonly MethodInfo TypeGetProperty = ExpressionUtility.GetMethodInfo((Type t) => t.GetTypeInfo().GetProperty(default(string)!, default(BindingFlags))); - internal static readonly MethodInfo TypeGetField = ExpressionUtility.GetMethodInfo((Type t) => t.GetTypeInfo().GetField(default(string)!, default(BindingFlags))); + internal static readonly MethodInfo TypeGetProperty = ExpressionUtility.GetMethodInfo((Type t) => t.GetProperty(default(string)!, default(BindingFlags))); + internal static readonly MethodInfo TypeGetField = ExpressionUtility.GetMethodInfo((Type t) => t.GetField(default(string)!, default(BindingFlags))); internal static readonly MethodInfo GetCustomAttributeMessagePackFormatterAttribute = ExpressionUtility.GetMethodInfo(() => CustomAttributeExtensions.GetCustomAttribute(default(MemberInfo)!, default(bool))); internal static readonly MethodInfo ActivatorCreateInstance = ExpressionUtility.GetMethodInfo(() => Activator.CreateInstance(default(Type)!, default(object[]))); @@ -1451,13 +1451,12 @@ private ObjectSerializationInfo(Type type, EmittableMemberAndConstructorParamete internal static ObjectSerializationInfo? CreateOrNull(Type type, bool forceStringKey, bool contractless, bool allowPrivate) { - TypeInfo ti = type.GetTypeInfo(); - var isClass = ti.IsClass || ti.IsInterface || ti.IsAbstract; - var isClassRecord = isClass && IsClassRecord(ti); - var isStruct = ti.IsValueType; + var isClass = type.IsClass || type.IsInterface || type.IsAbstract; + var isClassRecord = isClass && IsClassRecord(type); + var isStruct = type.IsValueType; - MessagePackObjectAttribute? contractAttr = ti.GetCustomAttributes().FirstOrDefault(); - DataContractAttribute? dataContractAttr = ti.GetCustomAttribute(); + MessagePackObjectAttribute? contractAttr = type.GetCustomAttributes().FirstOrDefault(); + DataContractAttribute? dataContractAttr = type.GetCustomAttribute(); if (contractAttr == null && dataContractAttr == null && !forceStringKey && !contractless) { return null; @@ -1672,11 +1671,12 @@ bool AddEmittableMemberOrIgnore(bool isIntKeyMode, EmittableMember member, bool // GetConstructor IEnumerator? ctorEnumerator = null; - ConstructorInfo? ctor = ti.DeclaredConstructors.SingleOrDefault(x => x.GetCustomAttribute(false) is not null); + ConstructorInfo? ctor = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly) + .SingleOrDefault(x => x.GetCustomAttribute(false) is not null); if (ctor == null) { - ctorEnumerator = - ti.DeclaredConstructors.Where(x => !x.IsStatic && (allowPrivate || x.IsPublic)).OrderByDescending(x => x.GetParameters().Length) + ctorEnumerator = (allowPrivate ? type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly) : + type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)).OrderByDescending(x => x.GetParameters().Length) .GetEnumerator(); if (ctorEnumerator.MoveNext()) @@ -1709,7 +1709,7 @@ bool AddEmittableMemberOrIgnore(bool isIntKeyMode, EmittableMember member, bool if (ctorParamIndexIntMembersDictionary.TryGetValue(ctorParamIndex, out paramMember)) { if ((item.ParameterType == paramMember.Type || - item.ParameterType.GetTypeInfo().IsAssignableFrom(paramMember.Type)) + item.ParameterType.IsAssignableFrom(paramMember.Type)) && paramMember.IsReadable) { constructorParameters.Add(new EmittableMemberAndConstructorParameter(paramMember, item)); @@ -1915,7 +1915,7 @@ private static IEnumerable GetAllProperties(Type type) } } - private static bool IsClassRecord(TypeInfo type) + private static bool IsClassRecord(Type type) { // The only truly unique thing about a C# 9 record class is the presence of a $ method, // which cannot be declared in C# because of the reserved characters in its name. diff --git a/src/MessagePack/Resolvers/DynamicUnionResolver.cs b/src/MessagePack/Resolvers/DynamicUnionResolver.cs index b65ca772d..9281c6667 100644 --- a/src/MessagePack/Resolvers/DynamicUnionResolver.cs +++ b/src/MessagePack/Resolvers/DynamicUnionResolver.cs @@ -68,44 +68,42 @@ private static class FormatterCache static FormatterCache() { - TypeInfo ti = typeof(T).GetTypeInfo(); - if (ti.IsNullable()) + Type type = typeof(T); + if (type.IsNullable()) { - ti = ti.GenericTypeArguments[0].GetTypeInfo(); + type = type.GenericTypeArguments[0]; - var innerFormatter = DynamicUnionResolver.Instance.GetFormatterDynamic(ti.AsType()); + var innerFormatter = DynamicUnionResolver.Instance.GetFormatterDynamic(type); if (innerFormatter == null) { return; } - Formatter = (IMessagePackFormatter?)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(ti.AsType()), new object[] { innerFormatter }); + Formatter = (IMessagePackFormatter?)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(type), new object[] { innerFormatter }); return; } - TypeInfo? formatterTypeInfo = BuildType(typeof(T)); + TypeInfo? formatterTypeInfo = BuildType(type); if (formatterTypeInfo == null) { return; } - Formatter = (IMessagePackFormatter?)Activator.CreateInstance(formatterTypeInfo.AsType()); + Formatter = (IMessagePackFormatter?)Activator.CreateInstance(formatterTypeInfo); } } private static TypeInfo? BuildType(Type type) { - TypeInfo ti = type.GetTypeInfo(); - // order by key(important for use jump-table of switch) - UnionAttribute[] unionAttrs = ti.GetCustomAttributes().OrderBy(x => x.Key).ToArray(); + UnionAttribute[] unionAttrs = type.GetCustomAttributes().OrderBy(x => x.Key).ToArray(); if (unionAttrs.Length == 0) { return null; } - if (!ti.IsInterface && !ti.IsAbstract) + if (!type.IsInterface && !type.IsAbstract) { throw new MessagePackDynamicUnionResolverException("Union can only be interface or abstract class. Type:" + type.Name); } @@ -283,7 +281,7 @@ private static void BuildSerialize(Type type, UnionAttribute[] infos, MethodBuil il.EmitLdarg(1); il.EmitLdarg(2); - if (item.Attr.SubType.GetTypeInfo().IsValueType) + if (item.Attr.SubType.IsValueType) { il.Emit(OpCodes.Unbox_Any, item.Attr.SubType); } @@ -387,7 +385,7 @@ private static void BuildDeserialize(Type type, UnionAttribute[] infos, MethodBu il.EmitLdarg(1); il.EmitLdarg(2); il.EmitCall(getDeserialize(item.Attr.SubType)); - if (item.Attr.SubType.GetTypeInfo().IsValueType) + if (item.Attr.SubType.IsValueType) { il.Emit(OpCodes.Box, item.Attr.SubType); } diff --git a/src/MessagePack/Resolvers/ImmutableCollectionResolver.cs b/src/MessagePack/Resolvers/ImmutableCollectionResolver.cs index de645990e..b7eb81dc5 100644 --- a/src/MessagePack/Resolvers/ImmutableCollectionResolver.cs +++ b/src/MessagePack/Resolvers/ImmutableCollectionResolver.cs @@ -63,18 +63,15 @@ internal static class ImmutableCollectionGetFormatterHelper internal static object? GetFormatter(Type t) { - TypeInfo ti = t.GetTypeInfo(); - - if (ti.IsGenericType) + if (t.IsGenericType) { - Type genericType = ti.GetGenericTypeDefinition(); - TypeInfo genericTypeInfo = genericType.GetTypeInfo(); - var isNullable = genericTypeInfo.IsNullable(); - Type? nullableElementType = isNullable ? ti.GenericTypeArguments[0] : null; + Type genericType = t.GetGenericTypeDefinition(); + var isNullable = genericType.IsNullable(); + Type? nullableElementType = isNullable ? t.GenericTypeArguments[0] : null; if (FormatterMap.TryGetValue(genericType, out Type? formatterType)) { - return CreateInstance(formatterType, ti.GenericTypeArguments); + return CreateInstance(formatterType, t.GenericTypeArguments); } else if (isNullable && nullableElementType?.IsConstructedGenericType is true && nullableElementType.GetGenericTypeDefinition() == typeof(ImmutableArray<>)) { @@ -97,5 +94,10 @@ public static bool IsNullable(this System.Reflection.TypeInfo type) { return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(System.Nullable<>); } + + public static bool IsNullable(this Type type) + { + return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(System.Nullable<>); + } } } diff --git a/src/MessagePack/Resolvers/SkipClrVisibilityChecks.cs b/src/MessagePack/Resolvers/SkipClrVisibilityChecks.cs index c6fdfccfc..17d463fef 100644 --- a/src/MessagePack/Resolvers/SkipClrVisibilityChecks.cs +++ b/src/MessagePack/Resolvers/SkipClrVisibilityChecks.cs @@ -76,39 +76,39 @@ internal SkipClrVisibilityChecks(AssemblyBuilder assemblyBuilder, ModuleBuilder /// Scans a given type for references to non-public types and adds any assemblies that declare those types /// to a given set. /// - /// The type which may be internal. + /// The type which may be internal. /// The set of assemblies to add to where non-public types are found. - internal static void GetSkipVisibilityChecksRequirements(TypeInfo typeInfo, ImmutableHashSet.Builder referencedAssemblies) + internal static void GetSkipVisibilityChecksRequirements(Type type, ImmutableHashSet.Builder referencedAssemblies) { - if (typeInfo.IsArray) + if (type.IsArray) { - GetSkipVisibilityChecksRequirements(typeInfo.GetElementType()!.GetTypeInfo(), referencedAssemblies); + GetSkipVisibilityChecksRequirements(type.GetElementType()!, referencedAssemblies); } - AddTypeIfNonPublic(typeInfo); + AddTypeIfNonPublic(type); - foreach (Type arg in typeInfo.GenericTypeArguments) + foreach (Type arg in type.GenericTypeArguments) { AddTypeIfNonPublic(arg); } // We must walk each base type individually to ensure we don't miss any private members, // since even with BindingFlags.NonPublic, GetMembers will not return from base types. - for (TypeInfo? target = typeInfo; target is not null; target = target.BaseType?.GetTypeInfo()) + for (Type? target = type; target is not null; target = target.BaseType) { ScanDirectType(target); } - void ScanDirectType(TypeInfo typeInfo) + void ScanDirectType(Type type) { - foreach (MemberInfo member in typeInfo.GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) + foreach (MemberInfo member in type.GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) { switch (member) { case FieldInfo field: if (!field.IsPublic) { - referencedAssemblies.Add(typeInfo.Assembly.GetName()); + referencedAssemblies.Add(type.Assembly.GetName()); } AddTypeIfNonPublic(field.FieldType); @@ -116,7 +116,7 @@ void ScanDirectType(TypeInfo typeInfo) case PropertyInfo property: if (property.SetMethod?.IsPublic is false || property.GetMethod?.IsPublic is false) { - referencedAssemblies.Add(typeInfo.Assembly.GetName()); + referencedAssemblies.Add(type.Assembly.GetName()); } AddTypeIfNonPublic(property.PropertyType); @@ -124,7 +124,7 @@ void ScanDirectType(TypeInfo typeInfo) case ConstructorInfo constructorInfo: if (!constructorInfo.IsPublic) { - referencedAssemblies.Add(typeInfo.Assembly.GetName()); + referencedAssemblies.Add(type.Assembly.GetName()); } foreach (ParameterInfo parameter in constructorInfo.GetParameters()) diff --git a/tests/MessagePack.SourceGenerator.Tests/Resources/UnionFormatter(Namespace)/Formatters.MessagePack.GeneratedMessagePackResolver.MyTestNamespace.IMyTypeFormatter.g.cs b/tests/MessagePack.SourceGenerator.Tests/Resources/UnionFormatter(Namespace)/Formatters.MessagePack.GeneratedMessagePackResolver.MyTestNamespace.IMyTypeFormatter.g.cs index be91b6294..f6e75173c 100644 --- a/tests/MessagePack.SourceGenerator.Tests/Resources/UnionFormatter(Namespace)/Formatters.MessagePack.GeneratedMessagePackResolver.MyTestNamespace.IMyTypeFormatter.g.cs +++ b/tests/MessagePack.SourceGenerator.Tests/Resources/UnionFormatter(Namespace)/Formatters.MessagePack.GeneratedMessagePackResolver.MyTestNamespace.IMyTypeFormatter.g.cs @@ -32,7 +32,7 @@ public void Serialize(ref MsgPack::MessagePackWriter writer, global::MyTestNames if (value != null && this.typeToKeyAndJumpMap.TryGetValue(value.GetType().TypeHandle, out keyValuePair)) { writer.WriteArrayHeader(2); - writer.WriteInt32(keyValuePair.Key); + writer.Write(keyValuePair.Key); switch (keyValuePair.Value) { case 0: diff --git a/tests/MessagePack.SourceGenerator.Tests/Resources/UnionFormatter(NestingClass)/Formatters.MessagePack.GeneratedMessagePackResolver.ContainingClass.IMyTypeFormatter.g.cs b/tests/MessagePack.SourceGenerator.Tests/Resources/UnionFormatter(NestingClass)/Formatters.MessagePack.GeneratedMessagePackResolver.ContainingClass.IMyTypeFormatter.g.cs index 63f0c831e..5fd854188 100644 --- a/tests/MessagePack.SourceGenerator.Tests/Resources/UnionFormatter(NestingClass)/Formatters.MessagePack.GeneratedMessagePackResolver.ContainingClass.IMyTypeFormatter.g.cs +++ b/tests/MessagePack.SourceGenerator.Tests/Resources/UnionFormatter(NestingClass)/Formatters.MessagePack.GeneratedMessagePackResolver.ContainingClass.IMyTypeFormatter.g.cs @@ -32,7 +32,7 @@ public void Serialize(ref MsgPack::MessagePackWriter writer, global::ContainingC if (value != null && this.typeToKeyAndJumpMap.TryGetValue(value.GetType().TypeHandle, out keyValuePair)) { writer.WriteArrayHeader(2); - writer.WriteInt32(keyValuePair.Key); + writer.Write(keyValuePair.Key); switch (keyValuePair.Value) { case 0: diff --git a/tests/MessagePack.SourceGenerator.Tests/Resources/UnionFormatter(None)/Formatters.MessagePack.GeneratedMessagePackResolver.IMyTypeFormatter.g.cs b/tests/MessagePack.SourceGenerator.Tests/Resources/UnionFormatter(None)/Formatters.MessagePack.GeneratedMessagePackResolver.IMyTypeFormatter.g.cs index 7d39b6866..b849b5ca4 100644 --- a/tests/MessagePack.SourceGenerator.Tests/Resources/UnionFormatter(None)/Formatters.MessagePack.GeneratedMessagePackResolver.IMyTypeFormatter.g.cs +++ b/tests/MessagePack.SourceGenerator.Tests/Resources/UnionFormatter(None)/Formatters.MessagePack.GeneratedMessagePackResolver.IMyTypeFormatter.g.cs @@ -31,7 +31,7 @@ public void Serialize(ref MsgPack::MessagePackWriter writer, global::IMyType val if (value != null && this.typeToKeyAndJumpMap.TryGetValue(value.GetType().TypeHandle, out keyValuePair)) { writer.WriteArrayHeader(2); - writer.WriteInt32(keyValuePair.Key); + writer.Write(keyValuePair.Key); switch (keyValuePair.Value) { case 0: diff --git a/tests/MessagePack.Tests/FormatterTest.cs b/tests/MessagePack.Tests/FormatterTest.cs index d74e4ba5e..fdb496b06 100644 --- a/tests/MessagePack.Tests/FormatterTest.cs +++ b/tests/MessagePack.Tests/FormatterTest.cs @@ -227,8 +227,12 @@ public void DateTimeOffsetTest() { string id = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "Tokyo Standard Time" : "Cuba"; DateTimeOffset now = new DateTime(DateTime.UtcNow.Ticks + TimeZoneInfo.FindSystemTimeZoneById(id).BaseUtcOffset.Ticks, DateTimeKind.Local); - var binary = MessagePackSerializer.Serialize(now); - MessagePackSerializer.Deserialize(binary).Is(now); + AssertRoundtrip(now); + + AssertRoundtrip(DateTimeOffset.Now); + + // Try specific offset values because CI/PR builds run on agents that run on the UTC time zone. + AssertRoundtrip(DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(4))); } [Fact] @@ -323,5 +327,21 @@ public void HalfTest() } #endif + + private static DateTimeOffset AssertRoundtrip(DateTimeOffset value) + { + var result = MessagePackSerializer.Deserialize(MessagePackSerializer.Serialize(value)); + result.Is(value, DateTimeOffsetEqualityComparer.Instance); + return result; + } + + private class DateTimeOffsetEqualityComparer : IEqualityComparer + { + internal static readonly DateTimeOffsetEqualityComparer Instance = new(); + + public bool Equals(DateTimeOffset x, DateTimeOffset y) => x.EqualsExact(y); + + public int GetHashCode(DateTimeOffset obj) => obj.UtcDateTime.GetHashCode(); + } } }