C# Generics: как использовать x.MaxValue / x.MinValue (int, float, double) в общем классе
Я использую расширенный инструментарий WPF (http://wpftoolkit.codeplex.com/).
У него есть хороший элемент управления NumericUpDown, который я хотел бы использовать, но внутри он использует Double - что означает, что он использует double.Minvalue и двойной.Максвеллову.
Я хотел бы использовать тот же элемент управления, но мне нужна общая версия - для ints он должен использовать int.MaxValue / MinValue, для поплавков поплавок.MaxValue / MinValue, etc. (Я думаю вы поняли :))
Так что я, хотя о копировании NumericUpDown в GNumericUpDown, где T, конечно, будет типом.. Но это не работает, потому что общий тип не имеет MinValue / MaxValue. И обычно я бы использовал предложение "where" для указания базового типа, но это не работает как afaik нет общего интерфейса, который определяет "MinValue" и "MaxValue".
есть ли способ решить эту проблему с помощью дженериков, или мне действительно нужно скопировать/вставить/найти и заменить исходный NumericUpDown для каждого типа ?
4 ответов
OP сделал этот комментарий к другому ответу:
Я хочу использовать эти элементы в моем код XAML. Моя идея заключалась в создании универсального версия, а затем создать пустые классы как NumericUpDownInt : GNumericUpDown { } это будет путь, или есть лучше / чище способ вашего знания
Если вы собираетесь идти по этому маршруту, просто передайте min и max напрямую:
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) { ... }
}
ну, учитывая, что вы можете получить тип во время выполнения, вы мог бы полагайтесь на то, что все числовые типы в .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
С этим типом вызовет исключение.
вы должны получить последний исходный код для расширенного инструментария WPF. Обновленный элемент управления numericupdown позволяет указать, какой тип данных использовать в Редакторе. Следующий код указывает использовать Int32 в качестве типа данных вместо double по умолчанию. Как вы можете видеть, это делается путем установки свойства ValueType в элементе управления NumericUpDown.
<extToolkit:NumericUpDown Grid.Row="1" Value="{Binding Age}" Increment="1" Minimum="18" Maximum="65" ValueType="{x:Type sys:Int32}" />
а это также полезно в сценариях тестирования:
вы можете использовать методы расширения, например, в C#6 (introducing 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 как константы. Использовать .