2012-01-13 30 views
7

Tóm lại: có thể xác định phương pháp chung trong đó tham số kiểu (T) bị giới hạn ở string hoặc int[]? Trong pseudo-C#, những gì tôi muốn làm là:Có thể hạn chế tham số kiểu generic thành String OR Array

public static int MyMethod<T> (T arg1, T arg2) 
    where T : (has an indexer that returns an int) { 
    // stuff with arg1[i], arg2[j], etc... 
} 

Lưu ý rằng trong C#, do được xây dựng trong string indexer (mà trả về một char) cùng với chuyển đổi ngầm từ char để int, biểu thức sau đây nghĩa một cách chính xác những điều tương tự dù source là một string hoặc một int[]:

int someval = source[index]; 

mỗi thread Constrain generic extension method to base types and string tôi nhận ra tôi không thể chỉ làm một danh sách các loại hủy liên kết giữa trongĐiều khoản ràng buộc. Cả hai int[]string sẽ tuân thủ T: IEnumerable<int>, nhưng IEnumerable<T> không yêu cầu người triển khai có trình chỉ mục, đó chính xác là tính năng phổ biến mà tôi đang sử dụng từ cả hai loại.

Mục đích của việc này là tôi đang xây dựng một số chức năng phân tích và phân tích cú pháp chuỗi được tối ưu hóa cao như triển khai nhanh thuật toán khoảng cách Damerau – Levenshtein. Tôi đã thấy rằng đầu tiên chuyển đổi chuỗi của tôi thành mảng int đôi khi có thể mang lại các thực thi nhanh hơn đáng kể trong việc xử lý ký tự từng ký tự lặp đi lặp lại (như với thuật toán D-L). Điều này phần lớn là do việc so sánh các giá trị int nhanh hơn nhiều so với các giá trị char.

Từ tác dụng là 'đôi khi'. Đôi khi nó hoạt động nhanh hơn trên dây và tránh chi phí chuyển đổi và sao chép đầu tiên thành mảng int. Vì vậy, bây giờ tôi có các phương pháp thực sự giống hệt ngoại trừ các khai báo.

Tất nhiên tôi có thể sử dụng dynamic, nhưng hình phạt hiệu suất từ ​​kiểm tra thời gian chạy hoàn toàn phá hủy mọi lợi ích được thực hiện trong việc xây dựng các phương pháp. (Tôi đã làm kiểm tra nó).

+0

Trong có ý nghĩa gì khi xử lý 'T' tĩnh như * hoặc * loại này hay kiểu khác? Điểm hạn chế là cho phép bạn hoạt động trên các biến kiểu 'T' và mong đợi mức độ tương thích kiểu tối thiểu. Ràng buộc với hai loại không tương thích lẫn nhau là bizzarre. –

+0

@ kirk-woll: Khi tôi mô tả chi tiết, chúng không tương thích lẫn nhau cho mục đích của tôi. Ngược lại, chúng giống hệt nhau. Tôi đã xây dựng và đang sử dụng các phương thức giống hệt 100%, ngoại trừ các tham số trong một phiên bản được khai báo là 'chuỗi' và trong phiên bản khác được khai báo là' int [] '. Trong cả hai trường hợp, tôi hoạt động trên mỗi thành viên của bộ sưu tập dưới dạng số nguyên. –

+1

Không. Một 'chuỗi' và (bất kỳ)' mảng 'thống nhất tại 'đối tượng', một chuỗi là * không * một' char [] 'trong C#, mặc dù bạn có thể tạo một' char [] '* từ * một chuỗi , nhưng đó là một đối tượng mảng * mới * với nội dung được sao chép. –

Trả lời

4

Bạn không thể có một ràng buộc cho biết "loại phải có một người lập chỉ mục".

Tuy nhiên, bạn có thể có ràng buộc cho biết “loại phải triển khai giao diện có trình chỉ mục”. Ví dụ, giao diện như vậy có thể là IList<char>.

Thật không may, string không thực hiện IList<char>, do đó bạn sẽ phải viết một lớp wrapper nhỏ cho nó:

sealed class StringWrapper : IList<char> 
{ 
    public string String { get; private set; } 
    public StringWrapper(string str) { String = str; } 
    public static implicit operator StringWrapper(string str) 
    { 
     return new StringWrapper(str); 
    } 

    public char this[int index] 
    { 
     get { return String[index]; } 
     set { throw new NotSupportedException(); } 
    } 

    // Etc.... need to implement all the IList<char> methods 
    // (just throw NotSupportedException except in the ones that are trivial) 
} 

Và sau đó bạn có thể khai báo phương pháp của bạn như thế này:

public static TElement MyMethod<TCollection, TElement>(TCollection arg) 
    where TCollection : IList<TElement> 
{ 
    return arg[0]; 
} 

[...] 

MyMethod<StringWrapper, char>("abc")  // returns 'a' 
MyMethod<int[], int>(new[] { 1, 2, 3 }) // returns 1 
+0

Điều này đã làm trong thực tế công việc. Một cách sử dụng rất thông minh của câu lệnh 'implicit operator'. Tôi đã sửa đổi ví dụ 'StringWrapper' để thực hiện' IList ', hạn chế các phương thức của tôi thành' T: IList 'và gọi các phương thức với cả hai đối số' string' và 'int []' được biên dịch thành công. Thật không may nó vẫn còn rất chậm, vì vậy tôi sẽ không thực sự được sử dụng nó. (Cả hai 'dynamic' và các phiên bản trình bao bọc' IList' được trình bày đều chậm hơn 2,8 lần so với 'int []' và 'string' overloads riêng biệt rõ ràng). –

+0

Tôi rất ngạc nhiên khi bạn nói nó chậm như 'năng động ', nhưng bạn dường như đã thử nghiệm nó, vì vậy tôi tin bạn. Tôi hy vọng điều này có nghĩa rằng năng động là đáng ngạc nhiên nhanh chóng, và không phải là phương thức giao tiếp công văn là đáng ngạc nhiên chậm. – Timwi

+0

Tôi đã thực hiện một số thử nghiệm khác nhau ngày hôm nay trên một tập hợp dữ liệu hetergenous lớn hơn, và kết quả của tôi trở lại rất khác nhau: chung chỉ chậm hơn 5% so với 'int []' quá tải; generic chỉ chậm hơn 15% so với quá tải 'string' rõ ràng; trong khi 'dynamic' chậm hơn khoảng 50% so với quá tải rõ ràng. –

5

Không, C# không cho phép bạn tạo ràng buộc "tổng hợp" như vậy.

Biểu thức bạn hiển thị không có nghĩa là giống nhau, nhưng bạn không thể sử dụng thực tế đó làm lợi thế của bạn. C# generics giống như C++ mẫu cú pháp, nhưng họ làm việc hoàn toàn khác nhau, do đó, thực tế là các lập chỉ mục không cùng một điều kết thúc lên là không liên quan.

Bạn có thể, tất nhiên, chỉ cần tạo hai quá tải với các loại cụ thể mà bạn cần, nhưng điều đó không có nghĩa là một số bản sao gây phiền nhiễu dán &. Bất kỳ nỗ lực nào trong việc trừu tượng hóa điều này để tránh sự lặp lại sẽ làm bạn mất hiệu suất.

0

Bạn có thể làm phương pháp chữ ký của bạn

public static int MyMethod<T> (T[] arg1, T[] arg2) 

và sử dụng String.ToCharArray() trước khi đi qua đối số chuỗi (hoặc có thể trong một tình trạng quá tải, bạn sẽ có được ý tưởng ...)

+0

Vấn đề duy nhất với điều này là OP là "xây dựng một số chức năng phân tích và phân tích cú pháp chuỗi được tối ưu hóa cao" - điều này sẽ không hề nhanh chút nào. –

+0

Than ôi, đánh bại mục đích sử dụng trình chỉ mục chuỗi - truy cập chỉ mục _without_ sao chép nội dung. Nếu tôi sẽ chuyển đổi sang một mảng, tôi sẽ chuyển đổi thành một mảng 'int', dễ dàng thực hiện với một phương thức mở rộng. –

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