C# Generics : how to use x.MaxValue / x.MinValue (int, float, double) in a generic class

前端 未结 4 1772
天涯浪人
天涯浪人 2021-01-05 03:59

I\'m using the WPF Extended Toolkit ( http://wpftoolkit.codeplex.com/ ).

It has a nice NumericUpDown control that I\'d like to use, but internally it uses doubles -

相关标签:
4条回答
  • 2021-01-05 04:22

    The OP made this comment on another answer:

    I want to use these controls in my XAML. My idea was to create a generic version, and then create empty classes like NumericUpDownInt : GNumericUpDown { } Would that be the way to go, or is there a better/cleaner way to your knowledge

    If you're going to go that route, then just pass the min and max directly:

    class abstract GenericNumericUpDown<T>
    {
        public GenericNumericUpDown(T min, T max) { ... }
    }
    
    class NumericUpDownInt : GenericNumericUpDown<int>
    {
        public NumericUpDownInt() : base(int.MinValue, int.MaxValue) { ... }
    }
    
    class NumericUpDownFloat : GenericNumericUpDown<float>
    {
        public NumericUpDownFloat() : base(float.MinValue, float.MaxValue) { ... }
    }
    
    class NumericUpDownDouble : GenericNumericUpDown<double>
    {
        public NumericUpDownDouble() : base(double.MinValue, double.MaxValue) { ... }
    }
    
    0 讨论(0)
  • 2021-01-05 04:32

    Well, given that you can get at the type at execution time, you could rely on the fact that all of the numeric types in .NET have MinValue and MaxValue fields, and read them with reflection. It wouldn't be terribly nice, but easy enough to do:

    using System;
    using System.Reflection;
    
    // Use constraints which at least make it *slightly* hard to use
    // with the wrong types...
    public class NumericUpDown<T> where T : struct,
        IComparable<T>, IEquatable<T>, IConvertible
    {
        public static readonly T MaxValue = ReadStaticField("MaxValue");
        public static readonly T MinValue = ReadStaticField("MinValue");
    
        private static T ReadStaticField(string name)
        {
            FieldInfo field = typeof(T).GetField(name,
                BindingFlags.Public | BindingFlags.Static);
            if (field == null)
            {
                // There's no TypeArgumentException, unfortunately. You might want
                // to create one :)
                throw new InvalidOperationException
                    ("Invalid type argument for NumericUpDown<T>: " +
                     typeof(T).Name);
            }
            return (T) field.GetValue(null);
        }
    }
    
    class Test
    {
        static void Main()
        {
            Console.WriteLine(NumericUpDown<int>.MaxValue); 
            Console.WriteLine(NumericUpDown<float>.MinValue);
        }
    }
    

    Note that if you use this with an inappropriate type, I've tried to force a compile-time error as best I can... but it won't be foolproof. If you manage to find a structure with all the right interfaces but without MinValue and MaxValue fields, then any attempt to use the NumericUpDown with that type will cause an exception to be thrown.

    0 讨论(0)
  • 2021-01-05 04:35

    As this is also useful in Testing scenarios:

    You may use extension methods, such that in C#6 (introducing nameof) you could write:

    public static class TypeExtension
    {
        public static T MinValue<T>(this Type self)
        {
            return (T)self.GetField(nameof(MinValue)).GetRawConstantValue();
        }
    
        public static T MaxValue<T>(this Type self)
        {
            return (T)self.GetField(nameof(MaxValue)).GetRawConstantValue();
        }
    
    }
    

    and invoke through some admittedly ugly syntax:

    var intMinValue = typeof(int).MinValue<int>();
    

    which in your generic method would be

    var typeMinValue = typeof(T).MinValue<T>();
    

    Note, that I am not certain that all primitive types declare their Min/Max values as constants. Use GetValue instead.

    0 讨论(0)
  • 2021-01-05 04:38

    You should get the latest source code for the Extended WPF Toolkit. The updated NumericUpDown control allows you to specify what data type to use in the editor. The following code specifies to use an Int32 as the data type instead of the default double. As you can see this is done by setting the ValueType property on the NumericUpDown control.

    <extToolkit:NumericUpDown Grid.Row="1" Value="{Binding Age}" Increment="1" Minimum="18" Maximum="65" ValueType="{x:Type sys:Int32}" /> 
    
    0 讨论(0)
提交回复
热议问题