2013-02-10 34 views
6

Tôi đang làm việc với một dự án nhỏ với một vài loại mảng khác nhau (ví dụ: double[], float[], int[]. vì vậy, tôi có nhiều chức năng mà trông như thế này bên dưới (giản thể cho ví dụ này - giả định tôi chỉ đối phó với mảng đơn chiều):Tại sao System.Array không thể là một ràng buộc kiểu?

void Print(float[] a) // prints an array of floats 
{ 
    for (int i = 0; i < a.Length; i++) 
    { 
     Console.Write(a[i]); 
    } 
} 

void Print(double[] a) // prints an array of doubles 
{ 
    for (int i = 0; i < a.Length; i++) 
    { 
     Console.Write(a[i]); 
    } 
} 

tôi, trong sự khôn ngoan vô hạn của tôi, nghĩ rằng tôi có thể làm giảm một số các sao chép mã bằng cách chỉ cần tạo phiên bản chung của các chức năng này. Vì vậy, tôi đã thử cách này:

void Print<T>(T t) where T : Array 
{ 
    for (int i = 0; i < t.Length; i++) 
    { 
     Console.Write(t.GetValue(i)); 
    } 
} 

Intellisense không phải là phàn nàn, nhưng trình biên dịch không thành công với một lỗi rất thú vị:

Constraint cannot be special class 'System.Array'

Tôi đã nhìn cho một lời giải thích (tương tự như Object hoặc niêm phong các lớp học, nhưng đã không tìm thấy nhiều, bên cạnh một đề cập đến on msdn. Bất cứ ai có thể giải thích cho tôi lý do tại sao đây là trường hợp? Tại sao tôi không thể chỉ định ràng buộc loại của System.Array?

ps: Trong khi gõ những dòng này ra, tôi nhận ra rằng tôi có thể thực hiện những gì tôi ban đầu muốn một cách dễ dàng hơn, với một chức năng đơn giản như thế này:

void Print(System.Array a) 
{ 
    for (int i = 0; i < a.Length; i++) 
    { 
     Console.Write(a.GetValue(i)); 
    } 
} 

Đây có phải là lý do tại sao có một quy tắc đặc biệt cho mảng trong trình biên dịch ?

Trả lời

16

Cú pháp thích hợp để làm những gì bạn muốn là thế này:

void Print<T>(T[] array) 
{ 
    for (int i = 0; i < array.Length; i++) 
    { 
     Console.Write(array[i]); 
    } 
} 
+1

Làm cho tinh thần, nhưng tôi vẫn tò mò _why_ Tôi không thể có một ràng buộc loại lớp cơ sở của 'Array' ... – vlad

+0

Ngoài ra, trong tò mò, là khác nhau từ việc sử dụng một tham số kiểu' Array'? Có chuyện gì xảy ra nếu tôi sử dụng 'Mảng'? – vlad

+1

@vlad Không có quyền anh vì các mảng là các kiểu tham chiếu, không phải là kiểu giá trị, mặc dù bạn đang đánh đấm các đối tượng mà bạn thoát khỏi nó, không giống như với một mảng được đánh máy. Nó cũng không giống nhau vì một mảng 'Array' cũng có thể là một mảng nhị phân 2, 3 hoặc N hoặc một mảng không được lập chỉ mục 0. – Servy

1

Nếu đưa ra những câu hỏi theo nghĩa đen, nó sẽ là vô ích để có một chế Array. Nó cũng giống như nó vô dụng khi có một ràng buộc ValueType, vì nó thực sự không kiểm tra xem bạn có sử dụng một loại giá trị làm đối số chung hay không, nhưng liệu kiểu bạn đang chuyển có thể gán cho ValueType hay không.
Vì vậy, bạn có thể chuyển ngay cả Array làm đối số chung và OK.

là gì thực sự hữu ích là phải có một mảng contraint cho phép bất kỳ loại có nguồn gốc từ Array, nhưng không Array bản thân:

void Print<TArr>(TArr t) where TArr : array //or [*] or other fancy syntax 

đâu T có thể [], [,], [,,], [,,,], vv trên. Tham số Array không chỉ chung chung là chúng ta biết loại phần tử của mảng.

Một cách khác để giải quyết việc này là tạo ra một lớp tùy chỉnh Array<T> với quá tải điều hành ngầm của T[], T[,], T[,,], vv

Edit:
Không có cách để đạt được điều này ngay cả trong CIL (hiện tại), bởi vì int[,]Array không khác nhau trong bất kỳ giao diện hoặc nhà xây dựng nào. Chúng ta cần sự ràng buộc where T : Array but not Array itself.

+0

Nó sẽ không hoàn toàn vô ích. Không phải vì lệnh cấm, người ta có thể viết một 'CopyAndReverseArraySegment (T dest, T source, int start, int length) trong đó T: System.Array' và có nó chấp nhận lời gọi nơi một hoặc cả nguồn hoặc đích là' System.Array', nhưng vẫn từ chối các lời gọi trong đó 'source' và' dest' là các kiểu mảng không tương thích. Vì nó là, tôi không tin rằng có một cách để cho phép 'System.Array' như là một loại đặc biệt cho một trong các tham số mà không có bất kỳ dẫn xuất của loại đó cũng được coi là chấp nhận được. – supercat

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