【问题标题】:C# Generics : how to use x.MaxValue / x.MinValue (int, float, double) in a generic classC# 泛型:如何在泛型类中使用 x.MaxValue / x.MinValue (int, float, double)
【发布时间】:2010-12-11 19:53:34
【问题描述】:

我正在使用 WPF 扩展工具包 (http://wpftoolkit.codeplex.com/)。

它有一个不错的 NumericUpDown 控件,我想使用它,但在内部它使用双精度 - 这意味着它使用 double.MinValue 和 double.MaxValue。

我想使用相同的控件,但我需要一个通用版本 - 对于整数,它需要使用 int.MaxValue/MinValue,对于浮点数 float.MaxValue/MinValue 等(我想你明白了: ))

所以我想将 NumericUpDown 复制到 GNumericUpDown,其中 T 当然是 Type.. 但这不起作用,因为泛型类型没有 MinValue / MaxValue。 通常我会使用“where”子句来指定基本类型,但这不起作用,因为没有定义“MinValue”和“MaxValue”的通用接口。

有没有办法用泛型解决这个问题,还是我真的需要复制/粘贴/搜索和替换每种类型的原始 NumericUpDown ?

【问题讨论】:

标签: c# generics floating-point int double


【解决方案1】:

好吧,鉴于您可以在执行时获取类型,您可以依赖于 .NET 中的所有数字类型都有 MinValueMaxValue 字段这一事实,并且仔细阅读它们。它不会非常好,但很容易做到:

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

请注意,如果您将它与不合适的类型一起使用,我会尽我所能强制编译时错误......但这不会万无一失。如果您设法找到具有所有正确接口但没有 MinValueMaxValue 字段的结构,那么任何尝试使用该类型的 NumericUpDown 都会导致抛出异常。

【讨论】:

  • 样品将不胜感激! :) 顺便说一句,乔恩,从你的反应时间来看——你是超人吗?你首先似乎知道的可能不是一切,而是接近它的东西——当像我这样的人遇到麻烦时,你似乎总是在那里 :) 干杯 :)
  • @IUsedToBeAPygmy:你很幸运 :) 我想我今晚要下网了……
  • 乔恩-首先,感谢您的出色输入-尚未对其进行测试,但即使它无法编译,您也给了我一个全新的思考方向:)但是就在我引起你注意的时候 ;) - 我想在我的 XAML 中使用这些控件。我的想法是创建一个通用版本,然后创建像 NumericUpDownInt 这样的空类:
  • @IUsedToBeAPygmy:恐怕我不知道泛型和 XAML 的混合效果如何。您可能会发现拥有一个通用基类很方便,但随后使用 DecimalUpDownInt32UpDown 等的子类型只是为了使 XAML 更简单。值得考虑作为备用计划:)(编辑:啊,我看到您编辑了您的评论以提出几乎相同的建议……所以至少,您和我一样疯狂,反之亦然:)
  • @siride:这里的反射只会对每种类型执行一次 - 并且考虑到所涉及的可能类型的数量(9,折扣字节和 sbyte)我会说使用 @987654329 的代码@(或其他)会不太清楚。
【解决方案2】:

OP 对另一个答案发表了此评论:

我想在我的 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) { ... }
}

【讨论】:

  • 嗯,当然。我很震惊,为什么我没有想到这一点。我认为这是思维过于复杂的情况之一,所以我错过了简单的解决方案。
【解决方案3】:

您应该获得扩展 WPF 工具包的最新源代码。更新后的 NumericUpDown 控件允许您指定要在编辑器中使用的数据类型。以下代码指定使用 Int32 作为数据类型,而不是默认的 double。如您所见,这是通过在 NumericUpDown 控件上设置 ValueType 属性来完成的。

<extToolkit:NumericUpDown Grid.Row="1" Value="{Binding Age}" Increment="1" Minimum="18" Maximum="65" ValueType="{x:Type sys:Int32}" /> 

【讨论】:

    【解决方案4】:

    因为这在测试场景中也很有用:

    您可以使用扩展方法,例如在 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

    【讨论】:

    • 只是一个旁注:这里的误导可能是 nameof(MinValue) 引用了您定义的方法 - 而不是 Type self 的最终 MinValue 属性 - 所以它并不是真的更好(如果有的话! ) 而不是显式使用"MinValue"
    猜你喜欢
    • 1970-01-01
    • 2021-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-08
    • 2010-10-15
    • 1970-01-01
    相关资源
    最近更新 更多