@@ -12,6 +12,14 @@ public static class ReflectionExtensions
1212 {
1313 private const BindingFlags bindingFlags = BindingFlags . Instance | BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . IgnoreCase ;
1414
15+ /// <summary>Gets the alignment of a type.</summary>
16+ public static int AlignOf < T > ( ) where T : unmanaged { unsafe { return sizeof ( AlignOfHelper < T > ) - sizeof ( T ) ; } }
17+
18+ /// <summary>Retrieves the non-<see cref="Nullable{T}"/> type for the provided type.</summary>
19+ /// <param name="type">The type.</param>
20+ /// <returns>If the type is <see cref="Nullable{T}"/>, returns <c>T</c>; otherwise, returns <paramref name="type"/>.</returns>
21+ public static Type AsNonNullable ( this Type type ) => type . IsNullable ( ) ? type . GetGenericArguments ( ) [ 0 ] : type ;
22+
1523 /// <summary>Converts the given value object to the specified type.</summary>
1624 /// <param name="value">The <see cref="object"/> to convert.</param>
1725 /// <param name="type">The <see cref="Type"/> to conver the <paramref name="value"/> paramter to.</param>
@@ -45,14 +53,14 @@ public static class ReflectionExtensions
4553 catch
4654 {
4755 // See if type has conversion constructor
48- var ci = type . GetConstructor ( new [ ] { value . GetType ( ) } ) ;
56+ var ci = type . GetConstructor ( [ value . GetType ( ) ] ) ;
4957 if ( ci is not null )
50- return ci . Invoke ( new [ ] { value } ) ;
58+ return ci . Invoke ( [ value ] ) ;
5159
5260 // See if type has static conversion method
53- var mi = type . GetMethod ( "op_Implicit" , new [ ] { value . GetType ( ) } ) ?? type . GetMethod ( "op_Explicit" , new [ ] { value . GetType ( ) } ) ;
61+ var mi = type . GetMethod ( "op_Implicit" , [ value . GetType ( ) ] ) ?? type . GetMethod ( "op_Explicit" , [ value . GetType ( ) ] ) ;
5462 if ( mi is not null )
55- return mi . Invoke ( null , new [ ] { value } ) ;
63+ return mi . Invoke ( null , [ value ] ) ;
5664
5765 // If both value and type are value types, and type is smaller, try to do binary conversion
5866 try
@@ -81,6 +89,13 @@ public static IEnumerable<Type> EnumInheritance(this Type type)
8189 yield return type = type . BaseType ;
8290 }
8391
92+ /// <summary>Gets the alignment of the type.</summary>
93+ public static int GetAlignment ( this Type type ) =>
94+ ( int ) typeof ( ReflectionExtensions ) . GetMethod ( nameof ( AlignOf ) , Type . EmptyTypes ) ! . MakeGenericMethod ( type ) . Invoke ( null , null ) ! ;
95+
96+ /// <summary>Gets the number of bits in the type's blitted value.</summary>
97+ public static int GetBitSize ( this Type type ) { unsafe { return Marshal . SizeOf ( type ) * 8 ; } }
98+
8499 /// <summary>Searches for the constants defined for <paramref name="type"/>, using the specified binding constraints.</summary>
85100 /// <param name="type">The type to search.</param>
86101 /// <param name="bindingFlags">A bitwise combination of the enumeration values that specify how the search is conducted.</param>
@@ -234,6 +249,37 @@ public static void InvokeMethod(this object? obj, string methodName, Type[] argT
234249 return ( T ? ) mi . Invoke ( obj , args ) ;
235250 }
236251
252+ /// <summary>Gets a value that determines if the type is an array that can be blitted.</summary>
253+ public static bool IsBlittableArray ( this Type ? type )
254+ {
255+ if ( type is null || ! type . IsArray || type . GetArrayRank ( ) != 1 )
256+ return false ;
257+ while ( type is not null && type . IsArray ) type = type . GetElementType ( ) ;
258+ return type . IsBlittablePrimitive ( ) ;
259+ }
260+
261+ /// <summary>Gets a value that determines if the field is a blittable type.</summary>
262+ public static bool IsBlittableField ( this FieldInfo fieldInfo ) => fieldInfo . FieldType . IsBlittablePrimitive ( ) || fieldInfo . FieldType == typeof ( bool ) || fieldInfo . FieldType . IsEnum || fieldInfo . FieldType . IsBlittableStruct ( ) ;
263+
264+ /// <summary>Gets a value that determines if the type is a primitive type that can be blitted.</summary>
265+ public static bool IsBlittablePrimitive ( this Type ? type ) => type is not null && ( IsIntegral ( type ) || IsNativeSized ( type ) || IsFloatingPoint ( type ) ) ;
266+
267+ /// <summary>Gets a value that determines if the type is a floating point type.</summary>
268+ public static bool IsFloatingPoint ( this Type ? type ) => Type . GetTypeCode ( type ) is TypeCode . Single or TypeCode . Double ;
269+
270+ /// <summary>Gets a value that determines if the type is an integral type.</summary>
271+ public static bool IsIntegral ( this Type ? type ) => Type . GetTypeCode ( type ) is >= TypeCode . SByte and <= TypeCode . UInt64 ;
272+
273+ /// <summary>Gets a value that determines if the type is <see cref="IntPtr"/> or <see cref="UIntPtr"/>.</summary>
274+ public static bool IsNativeSized ( this Type ? type ) => type == typeof ( IntPtr ) || type == typeof ( UIntPtr ) ;
275+
276+ /// <summary>Gets a value that determines if this integer is a factorial of 2.</summary>
277+ public static bool IsPow2 ( this int value )
278+ {
279+ if ( value < 0 ) throw new ArgumentOutOfRangeException ( nameof ( value ) , "Value must be positive." ) ;
280+ return value != 0 && ( value & ( value - 1 ) ) == 0 ;
281+ }
282+
237283 /// <summary>Sets a named field on an object.</summary>
238284 /// <typeparam name="T">The type of the field to be set.</typeparam>
239285 /// <typeparam name="TS">The type of the object on which to the set the field.</typeparam>
@@ -242,7 +288,7 @@ public static void InvokeMethod(this object? obj, string methodName, Type[] argT
242288 /// <param name="value">The field value to set on the object.</param>
243289 public static void SetFieldValue < T , TS > ( this TS ? obj , string fieldName , T ? value ) where TS : class
244290 {
245- try { obj ? . GetType ( ) . InvokeMember ( fieldName , BindingFlags . SetField | bindingFlags , null , obj , new object ? [ ] { value } , null ) ; }
291+ try { obj ? . GetType ( ) . InvokeMember ( fieldName , BindingFlags . SetField | bindingFlags , null , obj , [ value ] , null ) ; }
246292 catch { }
247293 }
248294
@@ -266,9 +312,18 @@ public static void SetFieldValue<T, TS>(this ref TS obj, string fieldName, T val
266312 /// <param name="value">The property value to set on the object.</param>
267313 public static void SetPropertyValue < T > ( this object obj , string propName , T value )
268314 {
269- try { obj ? . GetType ( ) . InvokeMember ( propName , BindingFlags . SetProperty | bindingFlags , null , obj , new object ? [ ] { value } , null ) ; }
315+ try { obj ? . GetType ( ) . InvokeMember ( propName , BindingFlags . SetProperty | bindingFlags , null , obj , [ value ] , null ) ; }
270316 catch { }
271317 }
318+
319+ private static bool IsBlittableStruct ( this Type ? type ) => type is not null && type . IsValueType && ! type . IsPrimitive && type . IsLayoutSequential && type . GetFields ( bindingFlags ) . All ( IsBlittableField ) ;
320+
321+ [ StructLayout ( LayoutKind . Sequential ) ]
322+ private struct AlignOfHelper < T > where T : unmanaged
323+ {
324+ public byte dummy ;
325+ public T data ;
326+ }
272327 }
273328}
274329
@@ -299,29 +354,6 @@ public static T CreateOrDefault<T>() where T : struct
299354 return default ;
300355 }
301356
302- /// <summary>Gets all loaded types in the <see cref="AppDomain"/>.</summary>
303- /// <param name="appDomain">The application domain.</param>
304- /// <returns>All loaded types.</returns>
305- public static IEnumerable < Type > GetAllTypes ( this AppDomain appDomain ) => appDomain . GetAssemblies ( ) . SelectMany ( a => a . GetTypes ( ) ) ;
306-
307- /// <summary>Returns an array of custom attributes applied to this member and identified by <typeparamref name="TAttr"/>.</summary>
308- /// <typeparam name="TAttr">The type of attribute to search for. Only attributes that are assignable to this type are returned.</typeparam>
309- /// <param name="element">An object derived from the MemberInfo class that describes a constructor, event, field, method, or property member of a class.</param>
310- /// <param name="inherit"><c>true</c> to search this member's inheritance chain to find the attributes; otherwise, <c>false</c>. This parameter is ignored for properties and events.</param>
311- /// <param name="predicate">An optional predicate to refine the results.</param>
312- /// <returns></returns>
313- public static IEnumerable < TAttr > GetCustomAttributes < TAttr > ( this MemberInfo element , bool inherit = false , Func < TAttr , bool > ? predicate = null ) where TAttr : Attribute =>
314- element . GetCustomAttributes ( typeof ( TAttr ) , inherit ) . Cast < TAttr > ( ) . Where ( predicate ?? ( a => true ) ) ;
315-
316- /// <summary>Returns an array of custom attributes applied to this member and identified by <typeparamref name="TAttr"/>.</summary>
317- /// <typeparam name="TAttr">The type of attribute to search for. Only attributes that are assignable to this type are returned.</typeparam>
318- /// <param name="type">The type of the <see cref="Type"/> to examine.</param>
319- /// <param name="inherit"><c>true</c> to search this member's inheritance chain to find the attributes; otherwise, <c>false</c>. This parameter is ignored for properties and events.</param>
320- /// <param name="predicate">An optional predicate to refine the results.</param>
321- /// <returns></returns>
322- public static IEnumerable < TAttr > GetCustomAttributes < TAttr > ( this Type type , bool inherit = false , Func < TAttr , bool > ? predicate = null ) where TAttr : Attribute =>
323- type . GetCustomAttributes ( typeof ( TAttr ) , inherit ) . Cast < TAttr > ( ) . Where ( predicate ?? ( a => true ) ) ;
324-
325357 /// <summary>Finds the type of the element of a type. Returns null if this type does not enumerate.</summary>
326358 /// <param name="type">The type to check.</param>
327359 /// <returns>The element type, if found; otherwise, <see langword="null"/>.</returns>
@@ -349,6 +381,29 @@ public static IEnumerable<TAttr> GetCustomAttributes<TAttr>(this Type type, bool
349381 bool ImplIEnumT ( Type t ) => t . IsGenericType && t . GetGenericTypeDefinition ( ) == typeof ( IEnumerable < > ) ;
350382 }
351383
384+ /// <summary>Gets all loaded types in the <see cref="AppDomain"/>.</summary>
385+ /// <param name="appDomain">The application domain.</param>
386+ /// <returns>All loaded types.</returns>
387+ public static IEnumerable < Type > GetAllTypes ( this AppDomain appDomain ) => appDomain . GetAssemblies ( ) . SelectMany ( a => a . GetTypes ( ) ) ;
388+
389+ /// <summary>Returns an array of custom attributes applied to this member and identified by <typeparamref name="TAttr"/>.</summary>
390+ /// <typeparam name="TAttr">The type of attribute to search for. Only attributes that are assignable to this type are returned.</typeparam>
391+ /// <param name="element">An object derived from the MemberInfo class that describes a constructor, event, field, method, or property member of a class.</param>
392+ /// <param name="inherit"><c>true</c> to search this member's inheritance chain to find the attributes; otherwise, <c>false</c>. This parameter is ignored for properties and events.</param>
393+ /// <param name="predicate">An optional predicate to refine the results.</param>
394+ /// <returns></returns>
395+ public static IEnumerable < TAttr > GetCustomAttributes < TAttr > ( this MemberInfo element , bool inherit = false , Func < TAttr , bool > ? predicate = null ) where TAttr : Attribute =>
396+ element . GetCustomAttributes ( typeof ( TAttr ) , inherit ) . Cast < TAttr > ( ) . Where ( predicate ?? ( a => true ) ) ;
397+
398+ /// <summary>Returns an array of custom attributes applied to this member and identified by <typeparamref name="TAttr"/>.</summary>
399+ /// <typeparam name="TAttr">The type of attribute to search for. Only attributes that are assignable to this type are returned.</typeparam>
400+ /// <param name="type">The type of the <see cref="Type"/> to examine.</param>
401+ /// <param name="inherit"><c>true</c> to search this member's inheritance chain to find the attributes; otherwise, <c>false</c>. This parameter is ignored for properties and events.</param>
402+ /// <param name="predicate">An optional predicate to refine the results.</param>
403+ /// <returns></returns>
404+ public static IEnumerable < TAttr > GetCustomAttributes < TAttr > ( this Type type , bool inherit = false , Func < TAttr , bool > ? predicate = null ) where TAttr : Attribute =>
405+ type . GetCustomAttributes ( typeof ( TAttr ) , inherit ) . Cast < TAttr > ( ) . Where ( predicate ?? ( a => true ) ) ;
406+
352407 /// <summary>Gets the fields of a structure with sequential layout in the order in which they appear in memory.</summary>
353408 /// <param name="type">The type of the structure.</param>
354409 /// <param name="bindingFlags">The binding flags.</param>
@@ -391,19 +446,6 @@ public static IEnumerable<FieldInfo> GetOrderedFields(this Type type, BindingFla
391446 return o . InvokeMethod < T > ( methodName , args ) ;
392447 }
393448
394- /// <summary>Invokes a named static method of a type with parameters.</summary>
395- /// <typeparam name="T">The expected type of the method's return value.</typeparam>
396- /// <param name="type">The type containing the static method.</param>
397- /// <param name="methodName">Name of the method.</param>
398- /// <param name="args">The arguments to provide to the method invocation.</param>
399- /// <returns>The value returned from the method.</returns>
400- public static T ? InvokeStaticMethod < T > ( this Type type , string methodName , params object ? [ ] ? args )
401- {
402- var argTypes = args == null || args . Length == 0 ? Type . EmptyTypes : Array . ConvertAll ( args , o => o ? . GetType ( ) ?? typeof ( object ) ) ;
403- var mi = type . GetMethod ( methodName , staticBindingFlags , null , argTypes , null ) ?? throw new ArgumentException ( @"Method not found" , nameof ( methodName ) ) ;
404- return ( T ? ) mi . Invoke ( null , args ) ;
405- }
406-
407449#if ! NETSTANDARD2_0
408450 /// <summary>Invokes a method from a derived base class.</summary>
409451 /// <param name="methodInfo">The <see cref="MethodInfo"/> instance from the derived class for the method to invoke.</param>
@@ -421,7 +463,7 @@ public static IEnumerable<FieldInfo> GetOrderedFields(this Type type, BindingFla
421463 returnType = methodInfo . ReturnType ;
422464
423465 var type = targetObject . GetType ( ) ;
424- var dynamicMethod = new DynamicMethod ( "" , returnType , new [ ] { type , typeof ( object ) } , type ) ;
466+ var dynamicMethod = new DynamicMethod ( "" , returnType , [ type, typeof ( object ) ] , type ) ;
425467 var iLGenerator = dynamicMethod . GetILGenerator ( ) ;
426468 iLGenerator . Emit ( OpCodes . Ldarg_0 ) ; // this
427469
@@ -442,10 +484,23 @@ public static IEnumerable<FieldInfo> GetOrderedFields(this Type type, BindingFla
442484 iLGenerator . Emit ( OpCodes . Call , methodInfo ) ;
443485 iLGenerator . Emit ( OpCodes . Ret ) ;
444486
445- return dynamicMethod . Invoke ( null , new [ ] { targetObject , arguments } ) ;
487+ return dynamicMethod . Invoke ( null , [ targetObject , arguments ] ) ;
446488 }
447489#endif
448490
491+ /// <summary>Invokes a named static method of a type with parameters.</summary>
492+ /// <typeparam name="T">The expected type of the method's return value.</typeparam>
493+ /// <param name="type">The type containing the static method.</param>
494+ /// <param name="methodName">Name of the method.</param>
495+ /// <param name="args">The arguments to provide to the method invocation.</param>
496+ /// <returns>The value returned from the method.</returns>
497+ public static T ? InvokeStaticMethod < T > ( this Type type , string methodName , params object ? [ ] ? args )
498+ {
499+ var argTypes = args == null || args . Length == 0 ? Type . EmptyTypes : Array . ConvertAll ( args , o => o ? . GetType ( ) ?? typeof ( object ) ) ;
500+ var mi = type . GetMethod ( methodName , staticBindingFlags , null , argTypes , null ) ?? throw new ArgumentException ( @"Method not found" , nameof ( methodName ) ) ;
501+ return ( T ? ) mi . Invoke ( null , args ) ;
502+ }
503+
449504 /// <summary>Determines whether the specified method is compatible with a delegate.</summary>
450505 /// <typeparam name="TDel">The type of the delegate.</typeparam>
451506 /// <param name="method">The method information.</param>
0 commit comments