Is there a constraint that restricts my generic method to numeric types?

后端 未结 21 2634
栀梦
栀梦 2020-11-21 05:48

Can anyone tell me if there is a way with generics to limit a generic type argument T to only:

  • Int16
  • Int32
相关标签:
21条回答
  • 2020-11-21 06:36

    If all you want is use one numeric type, you could consider creating something similar to an alias in C++ with using.

    So instead of having the very generic

    T ComputeSomething<T>(T value1, T value2) where T : INumeric { ... }
    

    you could have

    using MyNumType = System.Double;
    T ComputeSomething<MyNumType>(MyNumType value1, MyNumType value2) { ... }
    

    That might allow you to easily go from double to int or others if needed, but you wouldn't be able to use ComputeSomething with double and int in the same program.

    But why not replace all double to int then? Because your method may want to use a double whether the input is double or int. The alias allows you to know exactly which variable uses the dynamic type.

    0 讨论(0)
  • 2020-11-21 06:37

    Workaround using policies:

    interface INumericPolicy<T>
    {
        T Zero();
        T Add(T a, T b);
        // add more functions here, such as multiplication etc.
    }
    
    struct NumericPolicies:
        INumericPolicy<int>,
        INumericPolicy<long>
        // add more INumericPolicy<> for different numeric types.
    {
        int INumericPolicy<int>.Zero() { return 0; }
        long INumericPolicy<long>.Zero() { return 0; }
        int INumericPolicy<int>.Add(int a, int b) { return a + b; }
        long INumericPolicy<long>.Add(long a, long b) { return a + b; }
        // implement all functions from INumericPolicy<> interfaces.
    
        public static NumericPolicies Instance = new NumericPolicies();
    }
    

    Algorithms:

    static class Algorithms
    {
        public static T Sum<P, T>(this P p, params T[] a)
            where P: INumericPolicy<T>
        {
            var r = p.Zero();
            foreach(var i in a)
            {
                r = p.Add(r, i);
            }
            return r;
        }
    
    }
    

    Usage:

    int i = NumericPolicies.Instance.Sum(1, 2, 3, 4, 5);
    long l = NumericPolicies.Instance.Sum(1L, 2, 3, 4, 5);
    NumericPolicies.Instance.Sum("www", "") // compile-time error.
    

    The solution is compile-time safe. CityLizard Framework provides compiled version for .NET 4.0. The file is lib/NETFramework4.0/CityLizard.Policy.dll.

    It's also available in Nuget: https://www.nuget.org/packages/CityLizard/. See CityLizard.Policy.I structure.

    0 讨论(0)
  • 2020-11-21 06:37

    I would use a generic one which you could handle externaly...

    /// <summary>
    /// Generic object copy of the same type
    /// </summary>
    /// <typeparam name="T">The type of object to copy</typeparam>
    /// <param name="ObjectSource">The source object to copy</param>
    public T CopyObject<T>(T ObjectSource)
    {
        T NewObject = System.Activator.CreateInstance<T>();
    
        foreach (PropertyInfo p in ObjectSource.GetType().GetProperties())
            NewObject.GetType().GetProperty(p.Name).SetValue(NewObject, p.GetValue(ObjectSource, null), null);
    
        return NewObject;
    }
    
    0 讨论(0)
提交回复
热议问题