A game framework written with osu! in mind.
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add extension for getting nullable type cached

+24 -5
+3 -3
osu.Framework/Allocation/DependencyContainer.cs
··· 143 143 throw new ArgumentNullException(nameof(instance)); 144 144 } 145 145 146 - info = info.WithType(Nullable.GetUnderlyingType(type) ?? type); 146 + info = info.WithType(type.GetUnderlyingNullableType() ?? type); 147 147 148 148 var instanceType = instance.GetType(); 149 - instanceType = Nullable.GetUnderlyingType(instanceType) ?? instanceType; 149 + instanceType = instanceType.GetUnderlyingNullableType() ?? instanceType; 150 150 151 151 if (instanceType.IsValueType && !allowValueTypes) 152 152 throw new ArgumentException($"{instanceType.ReadableName()} must be a class to be cached as a dependency.", nameof(instance)); ··· 167 167 168 168 public object Get(Type type, CacheInfo info) 169 169 { 170 - info = info.WithType(Nullable.GetUnderlyingType(type) ?? type); 170 + info = info.WithType(type.GetUnderlyingNullableType() ?? type); 171 171 172 172 if (cache.TryGetValue(info, out var existing)) 173 173 return existing;
+2 -1
osu.Framework/Bindables/Bindable.cs
··· 8 8 using JetBrains.Annotations; 9 9 using Newtonsoft.Json; 10 10 using osu.Framework.Caching; 11 + using osu.Framework.Extensions.TypeExtensions; 11 12 using osu.Framework.IO.Serialization; 12 13 using osu.Framework.Lists; 13 14 ··· 237 238 /// <param name="input">The input which is to be parsed.</param> 238 239 public virtual void Parse(object input) 239 240 { 240 - Type underlyingType = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T); 241 + Type underlyingType = typeof(T).GetUnderlyingNullableType() ?? typeof(T); 241 242 242 243 switch (input) 243 244 {
+19 -1
osu.Framework/Extensions/TypeExtensions/TypeExtensions.cs
··· 2 2 // See the LICENCE file in the repository root for full licence text. 3 3 4 4 using System; 5 + using System.Collections.Concurrent; 5 6 using System.Collections.Generic; 6 7 using System.Linq; 7 8 using System.Reflection; ··· 88 89 return ret; 89 90 } 90 91 92 + private static readonly ConcurrentDictionary<Type, Type> underlying_type_cache = new ConcurrentDictionary<Type, Type>(); 93 + 91 94 /// <summary> 92 95 /// Determines whether the specified type is a <see cref="Nullable{T}"/> type. 93 96 /// </summary> 94 97 /// <remarks>See: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/nullable-types/how-to-identify-a-nullable-type</remarks> 95 - public static bool IsNullable(this Type type) => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); 98 + public static bool IsNullable(this Type type) => type.GetUnderlyingNullableType() != null; 99 + 100 + /// <summary> 101 + /// Gets the underlying type of a <see cref="Nullable{T}"/>. 102 + /// </summary> 103 + /// <remarks>This method is cached.</remarks> 104 + /// <param name="type">The potentially nullable type.</param> 105 + /// <returns>The underlying type, or null if one does not exist.</returns> 106 + public static Type GetUnderlyingNullableType(this Type type) 107 + { 108 + if (!type.IsGenericType) 109 + return null; 110 + 111 + // ReSharper disable once ConvertClosureToMethodGroup (see: https://github.com/dotnet/runtime/issues/33747) 112 + return underlying_type_cache.GetOrAdd(type, t => Nullable.GetUnderlyingType(t)); 113 + } 96 114 } 97 115 98 116 [Flags]