Search code examples
c#genericsinterface

How to detect if generic type parameter is a floating point type?


I have a generic method which serialises some numeric config entries. Additionally, only for floating point types it must store culture info along. How can I tell that template param is of floating point type?

Here's what I tried:

    public void Bar<T>() where T : System.Numerics.INumber<T> {
        T aa = default(T);
        
        // this is ugly
        if (aa is float || aa is double)
        {
        }
        
        // error: The type 'T' cannot be used as type parameter 'TSelf' in the generic type
        // or method 'IFloatingPoint<TSelf>'. There is no boxing conversion or type parameter
        // conversion from 'T' to 'System.Numerics.IFloatingPoint<T>'.
        if (aa is IFloatingPoint<T>)
        {
        }
        
        // works fine and IFloatingPoint<T> would also work if T was constrained to
        // IFloatingPoint<T> (but I need to accept also integer types)
        if (aa is INumber<T>)
        {
        }
        

    }

Can I somehow rephrase aa is IFloatingPoint<T> expression (or use something similar) to make it work and gracefully check T against being of floating-point-like? Similarly to C++'s

if constexpr (std::is_floating_point_v<T>) {
}

Solution

  • As an alternative to the answer provided by Sweeper, and since you mention the is_floating_point function from C++, you can replicate that functionality like this:

    public bool IsFloatingPoint<T>()
    {
        return typeof(T)
            .GetInterfaces()
            .Any(i => i.IsGenericType &&
                      i.GetGenericTypeDefinition() == typeof(IFloatingPoint<>));
    }
    

    And now in your Bar method:

    public void Bar<T>() 
        where T : System.Numerics.INumber<T>
    {
        if (IsFloatingPoint<T>())
        {
            // Do the floating point stuff
        }
    }