Reflection

Get all types that implement a given interface

public static IEnumerable<Type> GetTypesThatImplement<TInterface>(Assembly assembly,
                                                                    bool includeAbstract = false)
    where TInterface : class
{
    var types = assembly.GetTypes()
        .Where(t => t.IsAssignableTo(typeof(TInterface)) && !t.IsInterface);

    if (!includeAbstract)
        types = types.Where(t => !t.IsAbstract);

    return types;
}

Get assembly version

public static Version GetCurrentAssemblyVersion()
{
    return System.Reflection.Assembly.GetExecutingAssembly()
        .GetName()
        .Version
        ?? new Version(0, 0, 0, 0);
}

Check if a type is a record class

public static bool IsRecordType(Type type)
{
    if (!type.IsClass)
        return false;

    var searchFlags = System.Reflection.BindingFlags.Instance
            | System.Reflection.BindingFlags.Public
            | System.Reflection.BindingFlags.NonPublic;

    return type.GetProperty("EqualityContract", searchFlags) != null
        && type.GetMethod("<Clone>$", searchFlags) != null;
}

Check if a type is a ref struct

public static bool IsRefStruct(Type type)
{
    return type.IsByRefLike;
}

Create an instance of a type with optional property initializers

Notes:

  1. This method will fail with an exception if, the type has no parameterless constructor
  2. Reflection doesn't enforce that properties marked with the required keyword have to have a value set. If you don't set these values, then they can be null
  3. This method doesn't check property and value types. If you provide a wrong type of value in the propertyInitializers, then the method will fail with an exception.
public static T CreateInstance<T>(Type type,
                                    Dictionary<string, object>? propertyInitializers = null)
    where T: class
{
    if (typeof(T) != type)
        throw new ArgumentException("Type mismatch");

    T? instance = Activator.CreateInstance(type) as T
        ?? throw new InvalidOperationException("Failed to create instance");
    
    var searchFlags = System.Reflection.BindingFlags.Instance
                    | System.Reflection.BindingFlags.Public
                    | System.Reflection.BindingFlags.NonPublic;

    if (propertyInitializers != null)
    {
        foreach (var propery in propertyInitializers)
        {
            var propertyInfo = type.GetProperty(propery.Key, searchFlags)
                ?? throw new ArgumentException($"Property {propery.Key} not found");

            propertyInfo.SetValue(instance, propery.Value);
        }
    }

    return instance;
}