2010-12-11 38 views
7

Tôi đang sử dụng Bộ công cụ mở rộng WPF (http://wpftoolkit.codeplex.com/).C# Generics: cách sử dụng x.MaxValue/x.MinValue (int, float, double) trong một lớp chung

Nó có một điều khiển NumericUpDown tốt đẹp mà tôi muốn sử dụng, nhưng nội bộ nó sử dụng đôi - có nghĩa là nó sử dụng double.MinValue và double.MaxValue.

Tôi muốn sử dụng cùng một điều khiển, nhưng tôi cần một phiên bản chung - cho ints nó cần phải sử dụng int.MaxValue/MinValue, cho phao nổi.MaxValue/MinValue, v.v. (Tôi nghĩ bạn có ý tưởng :))

Vì vậy, tôi mặc dù sao chép NumericUpDown thành GNumericUpDown, trong đó T sẽ là loại .. Nhưng điều này không hiệu quả, vì Loại chung không có MinValue/MaxValue. Và thông thường tôi sẽ sử dụng mệnh đề 'where' để chỉ định kiểu cơ sở, nhưng điều này không hoạt động như afaik không có giao diện chung nào định nghĩa 'MinValue' và 'MaxValue'.

Có cách nào để giải quyết vấn đề này với generics hay tôi thực sự cần sao chép/dán/tìm kiếm & thay thế NumericUpDown gốc cho từng loại?

+1

Mối quan tâm lớn hơn của bạn sẽ là làm thế nào để làm số học với một loại chung ... xem [Công việc của Marc Gravell với cây biểu thị cho điều đó] (http://www.yoda.arachsys.com/csharp/genericoperators. html). –

Trả lời

9

Các OP đã nhận xét này về câu trả lời khác:

Tôi muốn sử dụng các điều khiển trong XAML của tôi. Ý tưởng của tôi là tạo ra một phiên bản generic , và sau đó tạo ra các lớp học trống như NumericUpDownInt: GNumericUpDown {} Đó có phải là con đường để đi, hoặc là có một tốt hơn/cách sạch hơn để kiến ​​thức của bạn

Nếu bạn định đi theo tuyến đường đó, thì chỉ cần chuyển min và max trực tiếp:

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

Vâng, ofcourse. Tôi bị sốc vì tại sao điều này không xảy ra với tôi. Tôi nghĩ đó là một trong những trường hợp suy nghĩ quá phức tạp nên tôi đã bỏ lỡ giải pháp đơn giản. – Pygmy

9

Vâng, cho rằng bạn có thể có được ở các loại tại thời gian thực hiện, bạn có thể dựa vào thực tế là tất cả các loại số trong .NET có MinValueMaxValue lĩnh vực, và đọc chúng với sự phản ánh. Nó sẽ không được tốt đẹp khủng khiếp, nhưng dễ dàng, đủ để làm:

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

Lưu ý rằng nếu bạn sử dụng điều này với một loại không thích hợp, tôi đã cố gắng ép một lỗi biên dịch tốt nhất có thể ... nhưng nó sẽ không được dễ dàng. Nếu bạn quản lý để tìm cấu trúc với tất cả các giao diện phù hợp nhưng không có các trường MinValueMaxValue thì bất kỳ nỗ lực nào để sử dụng NumericUpDown với loại đó sẽ gây ra ngoại lệ.

+0

Mẫu sẽ được đánh giá rất cao! :) Nhân tiện, Jon, đánh giá bởi trách nhiệm của bạn - bạn có siêu nhân tính không? Bạn trước hết dường như biết có lẽ không phải tất cả mọi thứ, nhưng một cái gì đó gần gũi với nó - và bạn dường như luôn luôn ở đó khi một người như tôi gặp rắc rối :) Chúc mừng :) – Pygmy

+0

@IUsedToBeAPygmy: Bạn thật may mắn :) Tôi nghĩ rằng tôi ' m sắp ra khỏi mạng cho đêm ... –

+0

Jon - trước hết, cảm ơn cho đầu vào tuyệt vời - chưa thử nghiệm nó, nhưng ngay cả khi nó sẽ không biên dịch bạn đã cho tôi một hướng hoàn toàn mới để suy nghĩ về :) Nhưng chỉ trong khi tôi có sự chú ý của bạn;) - Tôi muốn sử dụng các điều khiển trong XAML của tôi. Ý tưởng của tôi là tạo ra một phiên bản chung, và sau đó tạo ra các lớp trống như NumericUpDownInt: GNumericUpDown {} Đó có phải là cách để đi, hoặc là có một cách tốt hơn/sạch hơn với kiến ​​thức của bạn? – Pygmy

2

Bạn sẽ nhận được mã nguồn mới nhất cho Bộ công cụ mở rộng WPF. Điều khiển NumericUpDown được cập nhật cho phép bạn chỉ định loại dữ liệu nào sẽ sử dụng trong trình chỉnh sửa. Đoạn mã sau chỉ định sử dụng Int32 làm kiểu dữ liệu thay vì mặc định là double. Như bạn có thể thấy điều này được thực hiện bằng cách đặt thuộc tính ValueType trên điều khiển NumericUpDown.

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

Vì đây cũng rất hữu ích trong các tình huống kiểm tra:

Bạn có thể sử dụng phương pháp khuyến nông, như vậy trong C# 6 (giới thiệu nameof), bạn có thể viết:

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

} 

và gọi qua một số cú pháp được thừa nhận là xấu xí:

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

theo phương pháp chung của bạn ULD được

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

Lưu ý, rằng tôi không chắc chắn rằng tất cả các loại nguyên thủy tuyên bố giá trị Min/Max của họ như là hằng số. Sử dụng GetValue để thay thế.

Các vấn đề liên quan