| File: Internal\ImmutableTypeCache.cs | Web Access |
| Project: src\src\Libraries\Microsoft.Extensions.Caching.Hybrid\Microsoft.Extensions.Caching.Hybrid.csproj (Microsoft.Extensions.Caching.Hybrid) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.ComponentModel; using System.Reflection; #if NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER using System.Runtime.CompilerServices; #else using System.Runtime.InteropServices; using System.Runtime.Serialization; #endif namespace Microsoft.Extensions.Caching.Hybrid.Internal; /// <summary> /// Utility type for determining whether a type is blittable; the logic for this is very /// TFM dependent. /// </summary> internal static class ImmutableTypeCache { internal static bool IsBlittable<T>() // minimize the generic portion (twinned with IsTypeImmutable) { #if NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER return !RuntimeHelpers.IsReferenceOrContainsReferences<T>(); #else // down-level: only blittable types can be pinned try { // get a typed, zeroed, non-null boxed instance of the appropriate type // (can't use (object)default(T), as that would box to null for nullable types) object obj = FormatterServices.GetUninitializedObject(Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T)); GCHandle.Alloc(obj, GCHandleType.Pinned).Free(); return true; } catch { return false; } #endif } [System.Diagnostics.CodeAnalysis.SuppressMessage("Blocker Code Smell", "S2178:Short-circuit logic should be used in boolean contexts", Justification = "Non-short-circuiting intentional to remove unnecessary branch")] internal static bool IsTypeImmutable(Type type) { // check for known types if (type == typeof(string)) { return true; } if (type.IsValueType) { // switch from Foo? to Foo if necessary if (Nullable.GetUnderlyingType(type) is { } nullable) { type = nullable; } } if (type.IsValueType || (type.IsClass & type.IsSealed)) { // check for [ImmutableObject(true)]; note we're looking at this as a statement about // the overall nullability; for example, a type could contain a private int[] field, // where the field is mutable and the list is mutable; but if the type is annotated: // we're trusting that the API and use-case is such that the type is immutable return type.GetCustomAttribute<ImmutableObjectAttribute>() is { Immutable: true }; } // don't trust interfaces and non-sealed types; we might have any concrete // type that has different behaviour return false; } }