C # Generics: как использовать x.MaxValue / x.MinValue (int, float, double) в универсальном классе - PullRequest
7 голосов
/ 11 декабря 2010

Я использую WPF Extended Toolkit (http://wpftoolkit.codeplex.com/).

У него есть приятный элемент управления NumericUpDown, который я хотел бы использовать, но внутри он использует doubles - это означает, что он использует double.MinValue и double.MaxValue.

Я хотел бы использовать тот же элемент управления, но мне нужна универсальная версия - для целочисленных значений он должен использовать int.MaxValue / MinValue, для float float.MaxValue / MinValue и т. Д. (Думаю, вы поняли идею: ))

Так что я подумал о копировании NumericUpDown в GNumericUpDown, где T, конечно, будет типом .. Но это не работает, потому что универсальный тип не имеет MinValue / MaxValue. И обычно я бы использовал предложение 'where', чтобы указать базовый тип, но это не работает, так как на самом деле нет общего интерфейса, который определяет MinValue и MaxValue.

Есть ли способ решить эту проблему с помощью шаблонов или мне действительно нужно скопировать / вставить / найти и заменить исходный NumericUpDown для каждого типа?

Ответы [ 4 ]

9 голосов
/ 12 декабря 2010

ОП сделал этот комментарий к другому ответу:

Я хочу использовать эти элементы управления в моем XAML. Моя идея заключалась в том, чтобы создать общий версия, а затем создать пустые классы как NumericUpDownInt: GNumericUpDown {} Это будет путь, или есть лучший / чистый путь к вашим знаниям

Если вы собираетесь идти по этому маршруту, просто передайте мин и макс напрямую:

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) { ... }
}
9 голосов
/ 11 декабря 2010

Что ж, учитывая, что вы можете получить тип во время выполнения, вы можете полагаться на тот факт, что все числовые типы в .NET имеют поля MinValue и MaxValue, и читатьих с отражением.Это было бы ужасно приятно, но достаточно просто сделать:

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);
    }
}

Обратите внимание, что если вы используете это с неподходящим типом, я попытался сделать ошибку компиляции как можно лучше.... но это не будет надежно.Если вам удастся найти структуру со всеми правильными интерфейсами, но без полей MinValue и MaxValue, то любая попытка использовать NumericUpDown с этим типом вызовет исключение.

2 голосов
/ 17 декабря 2010

Вы должны получить последний исходный код для расширенного инструментария WPF. Обновленный элемент управления NumericUpDown позволяет указать, какой тип данных использовать в редакторе. Следующий код указывает на использование Int32 в качестве типа данных вместо двойного по умолчанию. Как вы можете видеть, это делается путем установки свойства ValueType в элементе управления NumericUpDown.

<extToolkit:NumericUpDown Grid.Row="1" Value="{Binding Age}" Increment="1" Minimum="18" Maximum="65" ValueType="{x:Type sys:Int32}" /> 
1 голос
/ 03 сентября 2016

Как это также полезно в сценариях тестирования:

Вы можете использовать методы расширения, например, в C # 6 (вводя nameof) вы можете написать:

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();
    }

}

и вызвать через какой-то заведомо уродливый синтаксис:

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

, который в вашем родовом методе будет

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

Обратите внимание, что я не уверен, что все примитивные типы объявляют свои значения Min / Max как константы. Вместо этого используйте GetValue.

...