2009-08-28 35 views
21

thể trùng lặp:
C# generic constraint for only integersCó ràng buộc chung về C# đối với các loại "số thực" không?

Greets!

Tôi đang cố gắng thiết lập hệ tọa độ Descartes trong C#, nhưng tôi không muốn giới hạn bản thân mình với bất kỳ loại số nào cho giá trị toạ độ của mình. Đôi khi chúng có thể là số nguyên và những lần khác chúng có thể là số hữu tỉ, tùy thuộc vào ngữ cảnh.

Điều này hét lên "lớp chung chung" với tôi, nhưng tôi stumped như thế nào để hạn chế loại cho cả tích phân và điểm nổi. Tôi dường như không thể tìm thấy một lớp học bao gồm bất kỳ khái niệm về số thực ...

public class Point<T> where T : [SomeClassThatIncludesBothIntsandFloats?] { 
    T myX, myY; 

    public Point(T x, T y) { 
     myX = x; 
     myY = y; 
    } 
} 

Point<int> pInt = new Point<int>(5, -10); 
Point<float> pFloat = new Point<float>(3.14159, -0.2357); 

Nếu tôi muốn mức độ tự do, tôi bầu cho một "typeof (T)" cơn ác mộng khi nói đến tính toán bên trong lớp học của tôi, loại bỏ bools, dây, đối tượng, vv? Hay tệ hơn, tôi có chọn làm một lớp cho từng loại số mà tôi muốn làm việc, mỗi loại có cùng một công thức toán học nội bộ không?

Mọi trợ giúp sẽ được đánh giá cao. Cảm ơn!

+10

Đây là một tính năng khá thường xuyên được yêu cầu. Chúng tôi đang xem xét nó như là một _possibility_ cho một bản phát hành giả định trong tương lai của trình biên dịch/thời gian chạy, nhưng nó không phải là siêu cao trong danh sách ưu tiên, vì vậy tôi sẽ không hiểu điều này như bất kỳ loại lời hứa nào. Hãy nhớ rằng, chúng tôi có hàng trăm tính năng có thể và bất kỳ bản phát hành cụ thể nào chỉ nhận được một số ít các tính năng đó. Nó chắc chắn trên radar của chúng tôi mặc dù. –

+1

Điều đó rất tốt để biết, Eric. Tôi rất mới với C#, nhưng tôi có nguồn gốc trong Java, vì vậy nó rất giống như kích thước nhảy ... tương tự, nhưng khác nhau, đủ để làm cho bạn đi "huh?" một lần trong một thời gian. ;) – Syndog

+3

Đối với những người khác, cảm ơn rất nhiều cho tất cả các câu trả lời của bạn. Các bạn là tất cả những điều này! Không có thắc mắc bất cứ lúc nào tôi Google một câu hỏi C#, stackoverflow.com xếp hạng rất nổi bật trong các kết quả. – Syndog

Trả lời

16

Bạn không thể xác định ràng buộc như vậy, nhưng bạn có thể kiểm tra loại khi chạy. Điều đó sẽ không giúp bạn thực hiện các phép tính.

Nếu bạn muốn làm các phép tính, một cái gì đó như thế này sẽ là một lựa chọn:

class Calculations<T, S> where S: Calculator<T>, new() 
{ 
    Calculator<T> _calculator = new S(); 

    public T Square(T a) 
    { 
     return _calculator.Multiply(a, a); 
    } 

} 

abstract class Calculator<T> 
{ 
    public abstract T Multiply(T a, T b); 
} 

class IntCalculator : Calculator<int> 
{ 
    public override int Multiply(int a, int b) 
    { 
     return a * b; 
    } 
} 

Tương tự như vậy, xác định một FloatCalculator và bất kỳ hoạt động mà bạn cần. Nó không phải là đặc biệt nhanh, mặc dù nhanh hơn so với C# 4.0 dynamic xây dựng.

var calc = new Calculations<int, IntCalculator>(); 
var result = calc.Square(10); 

Một tác dụng phụ là bạn sẽ chỉ có thể nhanh chóng Calculator nếu loại bạn vượt qua nó có phù hợp với Calculator<T> thực hiện, vì vậy bạn không cần phải làm kiểu thời gian chạy kiểm tra.

Điều này về cơ bản là những gì Hejlsberg đang đề cập đến trong số this interview nơi vấn đề được thảo luận. Cá nhân tôi vẫn muốn thấy một loại loại cơ sở nào đó :)

+1

Phải, điều đó có ý nghĩa. Về cơ bản bọc các loại "nguyên thủy" của tôi trong các lớp thực hiện một giao diện chung, sau đó hạn chế dựa trên đó. Cảm ơn, Thor! – Syndog

+0

Lưu ý rằng trong .NET 3.5 vẫn còn những thứ bạn có thể làm với Generics - xem câu trả lời của tôi để biết thêm. –

5

Đây là vấn đề đã biết, vì không có lớp học số học nào đến từ cùng một lớp. Vì vậy, bạn không thể hạn chế nó.

Điều duy nhất bạn có thể làm là

where T : struct 

nhưng thats không chính xác những gì bạn muốn.

Đây là liên kết đến vấn đề cụ thể.

Arithmetic types like int,double,decimal should implement IArithmetic<T>

+0

Hey Stan, chỉ muốn cho bạn biết rằng sẽ giúp khá nhiều. Trong một đột quỵ, làm cho T kế thừa từ cấu trúc loại bỏ sự cần thiết cho một kiểm tra thời gian chạy cho tất cả các loại giá trị. Cảm ơn, nụ! – Syndog

+2

Kết quả liên kết của bạn trong "không tìm thấy trang". – weberc2

0

Thi s có thể hữu ích. Bạn phải sử dụng một lớp chung để đạt được những gì bạn muốn.

0

C# hiện không cho phép loại ràng buộc về loại giá trị. tôi hỏi một câu hỏi liên quan cách đây không lâu.

Enum type constraints in C#

0

Điều này sẽ không tự cho vay khi có các lớp riêng biệt triển khai IPoint?

Cái gì như:

public interface IPoint<T> 
{ 
    T X { get; set; } 
    T Y { get; set; } 
} 

public class IntegerPoint : IPoint<int> 
{ 

    public int X { get; set; } 
    public int Y { get; set; } 
} 

Khi tính toán sẽ phải khác nhau về từng thực hiện nào phải không?

Dan #

+2

Vâng, các phép tính thực sự giống hệt nhau, bất kể chúng có được thực hiện hay không bằng cách sử dụng các giá trị số nguyên hoặc dấu phẩy động. Nếu không, tôi chỉ cần tạo ra hai lớp riêng biệt để thực hiện các kiểu tương ứng của chúng mà không có bất kỳ generics hoặc inheritance nào cả. Nhưng vì các công thức giống nhau, tôi không muốn lặp lại mã giữa các lớp. Cám ơn phản hồi của bạn! – Syndog

3

Bạn thực sự có thể làm được điều này, mặc dù giải pháp là tẻ nhạt để thiết lập, và có thể gây nhầm lẫn cho các nhà phát triển người không nhận thức được tại sao nó đã được thực hiện. (vì vậy nếu bạn chọn để làm tài liệu nó thououghly!) ...

Tạo hai cấu trúc, được gọi là, MyInt và MyDecimal hoạt động như mặt tiền cho CTS Int32 và các loại lõi thập phân (Chúng chứa trường nội bộ của loại tương ứng.) mỗi nên có một ctor rằng có một thể hiện của các loại lõi CTS như tham số đầu vào ..

hãy mỗi người thực hiện một giao diện trống gọi INumeric

Sau đó, trong phương pháp chung của bạn, hãy ràng buộc dựa trên giao diện này. Nhược điểm, ở khắp mọi nơi bạn muốn sử dụng các phương pháp này, bạn phải xây dựng một thể hiện của loại tùy chỉnh thích hợp thay vì loại CTS lõi và chuyển loại tùy chỉnh cho phương thức.

LƯU Ý: mã hóa các cấu trúc tùy chỉnh để mô phỏng tất cả hành vi của các loại CTS lõi là phần tẻ nhạt ... Bạn phải triển khai một số giao diện CLR tích hợp (IComparable, v.v.) và quá tải tất cả số học, và các toán tử boolean ...

12

Đây là một câu hỏi rất phổ biến; nếu bạn đang sử dụng .NET 3.5, có rất nhiều hỗ trợ cho điều này trong MiscUtil, thông qua lớp Operator, hỗ trợ các loại sẵn có và bất kỳ loại tùy chỉnh nào với toán tử (bao gồm toán tử "dỡ bỏ"); Đặc biệt, điều này cho phép sử dụng với Generics, ví dụ:

public static T Sum<T>(this IEnumerable<T> source) { 
    T sum = Operator<T>.Zero; 
    foreach (T value in source) { 
     if (value != null) { 
      sum = Operator.Add(sum, value); 
     } 
    } 
    return sum; 
} 

Hoặc ví dụ khác; Complex<T>

+0

Thú vị. Có vẻ như nó sử dụng chức năng cây biểu thức LINQ, nhưng ngay lập tức đánh giá từng bit? – Thorarin

+0

Nội bộ, nó sử dụng một cây biểu thức để biên dịch trước (chỉ một lần cho mỗi loại) một đại biểu có thể thực hiện phép tính số học. –

1

Bạn có thể nhận được gần gũi hơn với thực hiện thêm vài

public class Point<T> where T : struct, IComparable, IFormattable, IConvertible, 
           IComparable<T>, IEquatable<T> { 
} 

Chữ ký phù hợp với DateTime quá. Tôi không chắc liệu bạn có thể chỉ định nhiều loại hơn từ khung công tác hay không. Dù sao điều này chỉ giải quyết một phần của vấn đề. Để thực hiện các phép toán số cơ bản, bạn sẽ phải bọc các kiểu số và sử dụng các phương thức generic thay vì các toán tử chuẩn. See this SO question cho một vài tùy chọn.

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