Class TypeUtil
Provides static reflection utilities for type discovery, attribute retrieval, and type-relationship testing. All expensive reflection results are cached internally to make repeated lookups efficient. A single shared lock protects all caches, making every method thread-safe.
Inherited Members
Namespace: Scylla.Core.Util
Assembly: ScyllaCore.dll
Syntax
public static class TypeUtil
Remarks
Caching strategy: Three independent caches are maintained:
- Type cache: Maps full type name strings to resolved Type objects. Populated on first lookup via GetType(string).
-
Attribute cache: Two-level dictionary keyed first by
MemberInfo and then by attribute Type, storing
the raw Attribute arrays returned by
GetCustomAttributes. Populated on first attribute request. - Derived types cache: Maps base types to arrays of all types in all loaded assemblies that derive from or implement them. Populated on first request via GetDerivedTypes(Type).
All caches can be invalidated together via ClearCache(), which is necessary after dynamic assembly loading (e.g., hot-reload or plugin systems).
Assembly enumeration: The list of loaded assemblies from CurrentDomain is also cached after the first request and cleared by ClearCache(). Methods that enumerate assemblies (GetType(string), GetDerivedTypes(Type), GetTypesWithAttribute<T>()) handle ReflectionTypeLoadException gracefully, continuing with any partially loaded types rather than aborting.
Methods
ClearCache()
Invalidates all internal caches - the type name cache, the attribute cache, the derived-types cache, and the cached assembly list. After this call, the next lookup for any type, attribute, or derived-type query will perform a full reflection scan and repopulate the relevant cache from scratch.
Declaration
public static void ClearCache()
Remarks
Call this method after dynamically loading additional assemblies at runtime (e.g., via a plugin system or Unity's assembly hot-reload) to ensure that newly available types are discovered by subsequent queries. Under normal circumstances (static assembly graph) this method does not need to be called.
See Also
GetAttribute(MemberInfo, Type, int)
Retrieves a custom attribute of the specified attributeType from
member using a non-generic call pattern. The attribute array is
cached after the first call. Prefer the generic overload
GetAttribute<T>(MemberInfo, int) when the attribute type is known at
compile time.
Declaration
public static Attribute GetAttribute(MemberInfo member, Type attributeType, int index = 0)
Parameters
| Type | Name | Description |
|---|---|---|
| MemberInfo | member | The member to inspect. If |
| Type | attributeType | The Type of the attribute to search for. If |
| int | index | The zero-based index into the matching attribute array. Defaults to |
Returns
| Type | Description |
|---|---|
| Attribute | The Attribute at |
See Also
GetAttribute<T>(MemberInfo, int)
Retrieves a custom attribute of type T from the specified
member. The attribute array for this member/type combination is
cached after the first call. Use index to access additional
instances when the same attribute is applied more than once.
Declaration
public static T GetAttribute<T>(MemberInfo member, int index = 0) where T : Attribute
Parameters
| Type | Name | Description |
|---|---|---|
| MemberInfo | member | The MemberInfo (e.g., a Type, |
| int | index | The zero-based index into the array of matching attributes, for members where the
same attribute is applied multiple times. Defaults to |
Returns
| Type | Description |
|---|---|
| T | The attribute instance at |
Type Parameters
| Name | Description |
|---|---|
| T | The attribute type to retrieve. Must derive from Attribute. The result is cast to this type before being returned. |
See Also
GetAttributes<T>(MemberInfo)
Retrieves all custom attributes of type T applied to
member. The underlying attribute array is cached after the
first call; a typed copy is returned to the caller on each call to avoid
external mutation of the cache.
Declaration
public static T[] GetAttributes<T>(MemberInfo member) where T : Attribute
Parameters
| Type | Name | Description |
|---|---|---|
| MemberInfo | member | The member to inspect. If |
Returns
| Type | Description |
|---|---|
| T[] | An array of all |
Type Parameters
| Name | Description |
|---|---|
| T | The attribute type to retrieve. All instances of this type on the member are
returned, which is useful for attributes that allow multiple applications (i.e.,
those decorated with |
See Also
GetDerivedTypes(Type)
Returns all types in all currently loaded assemblies that derive from or implement
baseType. Results are cached keyed on baseType
after the first call. Handles ReflectionTypeLoadException in
partially-loaded assemblies by continuing with any types that did load successfully.
Declaration
public static Type[] GetDerivedTypes(Type baseType)
Parameters
| Type | Name | Description |
|---|---|---|
| Type | baseType | The base class or interface to search for. If |
Returns
| Type | Description |
|---|---|
| Type[] | A cached array of all derived or implementing types. Returns
Empty<T>() if |
Remarks
The first call for any given baseType scans every type in every
loaded assembly, which is expensive. Subsequent calls are O(1) cache lookups. If
assemblies are loaded dynamically after this call, call ClearCache() to
force a fresh scan on the next request.
See Also
GetDerivedTypes<T>()
Returns all types in all currently loaded assemblies that derive from or implement
T. Results are cached after the first call. For interface
types, any class or struct implementing the interface is included; for class types,
only strict subclasses are included (not T itself).
Declaration
public static Type[] GetDerivedTypes<T>()
Returns
| Type | Description |
|---|---|
| Type[] | An array of Type objects for all types that derive from or implement
|
Type Parameters
| Name | Description |
|---|---|
| T | The base class or interface to search for. Both abstract and concrete base types
are supported. Concrete instantiations of generic types (e.g.,
|
See Also
GetType(string)
Resolves a Type by its full name, first consulting the internal cache, then GetType(string), and finally performing a linear search through all assemblies loaded in the current AppDomain. The resolved type is stored in the cache for subsequent calls.
Declaration
public static Type GetType(string typeName)
Parameters
| Type | Name | Description |
|---|---|---|
| string | typeName | The fully qualified name of the type to resolve (e.g.,
|
Returns
| Type | Description |
|---|---|
| Type | The resolved Type, or |
Remarks
This method is thread-safe. All callers share the same cache, so the first caller to resolve a particular name pays the full reflection cost; subsequent callers return the cached result immediately.
See Also
GetTypesWithAttribute<T>()
Returns all types in all currently loaded assemblies that have at least one custom
attribute of type T applied at the class/struct/enum level.
Unlike GetDerivedTypes<T>(), this method does not cache its
result, so repeated calls re-scan all assemblies each time.
Declaration
public static Type[] GetTypesWithAttribute<T>() where T : Attribute
Returns
| Type | Description |
|---|---|
| Type[] | A freshly allocated array of all types in any loaded assembly whose type-level
declaration is decorated with at least one |
Type Parameters
| Name | Description |
|---|---|
| T | The attribute type to search for. Only top-level type declarations are inspected;
members (methods, properties, fields) within those types are not tested.
The search uses IsDefined(Type, bool) with |
Remarks
Because this method does not cache results, it is suitable for scenarios where the set of loaded assemblies changes frequently or where the overhead is only incurred once at startup. For performance-critical or frequently repeated calls, consider caching the result yourself.
See Also
GetUnderlyingTypeOrSelf(Type)
Returns the underlying value type of a nullable type, or the type itself if it is not nullable. Useful for normalizing types when processing a mix of nullable and non-nullable value types through the same code path.
Declaration
public static Type GetUnderlyingTypeOrSelf(this Type type)
Parameters
| Type | Name | Description |
|---|---|---|
| Type | type | The type to unwrap. If |
Returns
| Type | Description |
|---|---|
| Type | GetUnderlyingType(Type) of |
See Also
HasAttribute<T>(MemberInfo)
Returns true if member has at least one custom attribute
of type T applied to it. Delegates to
GetAttribute<T>(MemberInfo, int) and checks for a non-null result.
Declaration
public static bool HasAttribute<T>(MemberInfo member) where T : Attribute
Parameters
| Type | Name | Description |
|---|---|---|
| MemberInfo | member | The member to inspect. If |
Returns
| Type | Description |
|---|---|
| bool |
|
Type Parameters
| Name | Description |
|---|---|
| T | The attribute type to check for. |
See Also
IsNullable(Type)
Determines whether type is a closed Nullable<T>
value type (i.e., a struct wrapped with ? syntax such as int?).
Implemented as a Type extension method.
Declaration
public static bool IsNullable(this Type type)
Parameters
| Type | Name | Description |
|---|---|---|
| Type | type | The type to test. If |
Returns
| Type | Description |
|---|---|
| bool |
|
See Also
IsSubclassOfRawGeneric(Type, Type)
Determines whether toCheck derives from baseType
when baseType is an open generic type (a generic type definition
without type arguments, such as typeof(List<>)). The standard
IsSubclassOf(Type) and IsAssignableFrom(Type) cannot handle
this case; this extension method walks the inheritance chain manually, stripping type
arguments at each step via GetGenericTypeDefinition().
Declaration
public static bool IsSubclassOfRawGeneric(this Type toCheck, Type baseType)
Parameters
| Type | Name | Description |
|---|---|---|
| Type | toCheck | The type to test. May be a concrete generic instantiation (e.g.,
|
| Type | baseType | The open or closed generic base type to check against. Pass the raw generic
definition (e.g., |
Returns
| Type | Description |
|---|---|
| bool |
|
Remarks
This is implemented as a Type extension method so it can be called
directly on a type instance: someType.IsSubclassOfRawGeneric(typeof(Base<>)).
TryGetType(string, out Type)
Attempts to resolve a Type by its full name, returning a boolean
indicating success rather than requiring the caller to check for a null
return value. Internally delegates to GetType(string).
Declaration
public static bool TryGetType(string typeName, out Type type)
Parameters
| Type | Name | Description |
|---|---|---|
| string | typeName | The fully qualified name of the type to find (e.g., |
| Type | type | When this method returns |
Returns
| Type | Description |
|---|---|
| bool |
|