2012-01-17 36 views
32

Không có sự khác biệt giữa hai dòng này, bởi vì trình biên dịch, trong dòng thứ hai, hiểu rằng nó là một mảng kiểu int.Tại sao trình biên dịch không chuyển đổi var [] thành đối tượng [] trong C#?

var x = new int[] { 1, 2, 3 }; //Fine, x is int[] 
var x = new [] { 1, 2, 3 };  //Fine, x is int[] 

Nhưng tại sao tôi không thể làm điều này với các loại khác nhau? Tại sao trình biên dịch không chuyển đổi biến của tôi thành loại đối tượng?

var x = new object[] { 1, "df", 5 }; //Fine, x is object[] 
var x = new [] { 1, "df", 5 };   //Error! "No best type found for implicity-typed-array" 

EDIT:

Cảm ơn tất cả những câu trả lời của bạn. Nhưng tôi vẫn tự hỏi, những ưu điểm và khuyết điểm là gì để làm cho tất cả các biểu thức mà trình biên dịch không thể chuyển đổi thành loại object? (Bởi vì tôi sử dụng ký hiệu var có nghĩa là nó không thể là bất kỳ loại nào. Tôi hiểu như thế này.) Tại sao trình biên dịch không tìm thấy loại gần nhất của các thành viên mảng bằng cách đi lên cây thừa kế?

+2

Bạn đã đọc thông số C# chưa? – BoltClock

+0

Có, nhưng câu hỏi chủ yếu là "tại sao nó không được thực hiện theo cách này?" –

+2

Damien_The_Unbeliever bình luận về câu trả lời của Joey nói tất cả, thực sự. Nó chỉ là quá nhiều công việc cho trình biên dịch, chưa kể đến việc suy luận 'đối tượng []' kết quả là khá trực quan đối với tôi. – BoltClock

Trả lời

38

Ký hiệu new [] là để lưu bạn nhập loại rõ ràng của các thành viên mảng (hoặc cho phép bạn tạo mảng nơi phần tử của nó có loại ẩn danh), nhưng suy luận kiểu của nó bị giới hạn ở chỗ tất cả các phần tử phải chia sẻ giống nhau nhập hoặc chuyển đổi hoàn toàn thành loại chung được chia sẻ bởi ít nhất một thành viên. Xem Thông số kỹ thuật C#, phần 7.6.10.4:

Biểu thức tạo mảng của biểu mẫu thứ ba được gọi là biểu thức tạo mảng được nhập hoàn toàn. Nó tương tự như dạng thứ hai, ngoại trừ loại phần tử của mảng không được đưa ra một cách rõ ràng, nhưng được xác định là loại phổ biến nhất (§7.5.2.14) của tập các biểu thức trong bộ khởi tạo mảng.

Sau đây là ví dụ về biểu thức tạo mảng ngầm gõ:

var a = new[] { 1, 10, 100, 1000 };      // int[] 
var b = new[] { 1, 1.5, 2, 2.5 };       // double[] 
var c = new[,] { { "hello", null }, { "world", "!" } }; // string[,] 
var d = new[] { 1, "one", 2, "two" };      // Error 

Biểu thức cuối cùng gây ra một lỗi biên dịch-thời gian vì không phải int cũng không string là mặc nhiên chuyển đổi cho người kia, và do đó không tốt nhất là chung kiểu. Biểu thức tạo mảng được nhập rõ ràng phải được sử dụng trong trường hợp này, ví dụ: chỉ định loại là object[]. Ngoài ra, một trong các thành phần có thể được truyền sang loại cơ sở chung, sau đó sẽ trở thành loại phần tử phỏng đoán.

Điểm quan trọng ở đây là "loại phổ biến nhất" chỉ có thể là một trong các loại đã có. Như Damien_The_Unbeliever chỉ ra trong một bình luận: “Như ông Lippert thích chỉ ra xung quanh suy luận, bất cứ khi nào nó tìm kiếm một loại phổ biến nhất, nó sẽ chỉ trả lại một trong những loại đã có mặt - nó không đi săn cho tổ tiên chung có nguồn gốc nhiều nhất. ”.

Chỉ vì mọi mảng có thể là object [] không có nghĩa là nó nên. Theo quan điểm của trình biên dịch, đó sẽ là một lựa chọn cuối cùng tầm thường, nhưng một sự lựa chọn rất trực quan cho nhà phát triển, tôi đoán vậy.

+0

Và tại sao [] mới không được triển khai để cung cấp sự hội tụ như vậy? Các nhược điểm của điều đó là gì? –

+0

Không, ký pháp [] mới chủ yếu cho các mảng sắp xếp các loại vô danh. Tiết kiệm đánh máy chỉ là một hiệu ứng phụ tốt đẹp. – Stilgar

+0

* Lý do * có thể là điều mà Eric Lippert có thể trả lời. Tôi là một chút mờ về lịch sử nhưng suy luận kiểu toàn diện đi kèm với 'var', có thể' mới [] 'trước đó. – Joey

18

Để mở rộng về câu trả lời của Joey, hãy xem xét ví dụ sau:

interface IFoo { } 
interface IBar { } 

class A : IFoo, IBar { } 
class B : IFoo, IBar { } 

var array = new [] { new A(), new B() }; 

Cả lớp thực hiện cả hai giao diện (và cũng có thể xuất phát từ object), vì vậy mà loại nên được suy ra cho array?


Để trả lời bình luận của bạn, hãy xem xét trường hợp AB phần chỉ có một giao diện:

interface IFoo { } 

class A : IFoo { } 
class B : IFoo { } 

var array = new [] { new A(), new B() }; 

Cả AB phần object như lớp cơ sở của họ, nhưng nó muốn được vô ích và chủ yếu vô dụng để suy ra điều này cho loại mảng. Người ta sẽ mong đợi nó là IFoo nếu có, vì vậy nó sẽ vi phạm principle of least astonishment. Tuy nhiên, điều này không thể được thực hiện nhất quán, như tôi đã minh họa.

Hành vi an toàn nhất và phù hợp nhất ở đây đơn giản là không cho phép suy luận kiểu.

+1

+1. Chúng tôi luôn có xu hướng quên rằng .NET * không * hỗ trợ đa kế thừa (mặc dù chỉ thông qua giao diện). – Heinzi

+1

Vâng, ví dụ tốt. Nhưng tại sao trong ví dụ này, anh ta không thể chuyển đổi thành đối tượng. Anh ta có thể tìm thấy loại gần nhất mà cả hai đều được thừa hưởng. Không có nhiều thừa kế, vì vậy anh ta có thể tìm kiếm bằng một nhánh cây duy nhất ... –

+0

@mesiesta: Chúng chỉ có một lớp * cơ bản chung, nhưng tại sao điều này lại được ưu tiên hơn các giao diện được triển khai của chúng? Giao diện cũng là các loại. –

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