2008-09-05 32 views
44

C# không đòi hỏi bạn phải xác định một tham số kiểu generic nếu trình biên dịch có thể suy ra nó, ví dụ:Tại sao không hỗ trợ C# ngụ ý các loại chung trên các nhà xây dựng lớp?

List<int> myInts = new List<int> {0,1,1, 
    2,3,5,8,13,21,34,55,89,144,233,377, 
    610,987,1597,2584,4181,6765}; 

//this statement is clunky 
List<string> myStrings = myInts. 
    Select<int,string>(i => i.ToString()). 
    ToList<string>(); 

//the type is inferred from the lambda expression 
//the compiler knows that it's taking an int and 
//returning a string 
List<string> myStrings = myInts. 
    Select(i => i.ToString()). 
    ToList(); 

này là cần thiết cho các loại vô danh mà bạn không biết những gì các tham số kiểu sẽ là (trong intellisense nó hiển thị như 'a) bởi vì nó được thêm vào bởi trình biên dịch. tham số kiểu

Lớp cấp không cho phép bạn làm điều này:

//sample generic class 
public class GenericDemo<T> 
{ 
    public GenericDemo (T value) 
    { 
     GenericTypedProperty = value; 
    } 

    public T GenericTypedProperty {get; set;} 
} 

//why can't I do: 
int anIntValue = 4181; 
var item = new GenericDemo(anIntValue); //type inference fails 

//however I can create a wrapper like this: 
public static GenericDemo<T> Create<T> (T value) 
{ 
    return new GenericDemo<T> (value); 
} 

//then this works - type inference on the method compiles 
var item = Create(anIntValue); 

Tại sao không C# hỗ trợ mức lớp này chung chung kiểu suy luận?

+0

Tại sao câu hỏi này có một cuộc bỏ phiếu để chống lại nó như là một bản sao của [Tại sao không thể loại suy luận hàm tạo C#?] (http://stackoverflow.com/questions/3570167) khi câu hỏi đó là hai năm gần đây hơn? Chắc chắn đó là bản sao? – Keith

+0

Tôi nghĩ rằng câu hỏi khác là ngắn gọn hơn, và nó có một câu trả lời tốt hơn. – Sam

+0

@Sam - vâng, câu trả lời của Eric Lippert cho câu hỏi đó là có thẩm quyền, nhưng tôi không nghĩ một trong hai câu hỏi nên được đóng lại. – Keith

Trả lời

25

Thực ra, câu hỏi của bạn không tệ. Tôi đã chơi đùa với một ngôn ngữ lập trình chung trong vài năm qua và mặc dù tôi chưa bao giờ thực sự phát triển nó (và có lẽ sẽ không bao giờ), tôi đã suy nghĩ rất nhiều về suy luận kiểu chung và một trong những ưu tiên hàng đầu của tôi luôn cho phép xây dựng các lớp mà không cần phải chỉ định loại chung.

C# đơn giản là thiếu tập hợp các quy tắc để làm điều này có thể. Tôi nghĩ rằng các nhà phát triển không bao giờ thấy sự cần thiết để bao gồm điều này. Trên thực tế, các mã sau đây sẽ rất gần với đề xuất của bạn và giải quyết vấn đề. Tất cả các nhu cầu C# là một sự hỗ trợ cú pháp được thêm vào.

class Foo<T> { 
    public Foo(T x) { … } 
} 

// Notice: non-generic class overload. Possible in C#! 
class Foo { 
    public static Foo<T> ctor<T>(T x) { return new Foo<T>(x); } 
} 

var x = Foo.ctor(42); 

Vì mã này thực sự hoạt động, chúng tôi đã chỉ ra rằng vấn đề không phải là ngữ nghĩa mà chỉ đơn giản là một vấn đề thiếu hỗ trợ. Tôi đoán tôi phải lấy lại bài viết trước đây của tôi. ;-)

11

Tại sao C# không hỗ trợ suy luận kiểu chung loại cấp lớp này?

Vì chúng thường không rõ ràng. Ngược lại, suy luận kiểu là tầm thường đối với các cuộc gọi hàm (nếu tất cả các kiểu xuất hiện trong các đối số). Nhưng trong trường hợp các cuộc gọi hàm tạo (các hàm được vinh danh, vì mục đích thảo luận), trình biên dịch phải giải quyết nhiều cấp cùng một lúc. Một cấp là cấp độ lớp và cấp độ kia là cấp đối số hàm tạo. Tôi tin rằng việc giải quyết điều này là không đáng kể về mặt thuật toán. Trực giác, tôi muốn nói nó thậm chí NP-hoàn thành.

Để minh họa một trường hợp cực đoan, nơi có độ phân giải là không thể, hãy tưởng tượng lớp sau và cho tôi biết những gì các trình biên dịch nên làm:

class Foo<T> { 
    public Foo<U>(U x) { } 
} 

var x = new Foo(1); 
+0

Từ cách câu hỏi của Konrad được xây dựng, tôi đã biết rằng loại "int" không thể đơn giản được suy ra từ "mới Foo (1)" - ví dụ, nhưng bất cứ ai có thể giải thích cho tôi tại sao không? Tôi có nghĩa là, nếu tôi nói "var x = 1", tôi kết thúc với một int, vậy làm thế nào là khác nhau từ ví dụ này? –

+0

Tôi không nghĩ * Bởi vì chúng thường mơ hồ * là một lý do rất tốt; các phương thức chung cũng không rõ ràng, với sự hiện diện của các phương thức không chung chung với cùng chữ ký. – Sam

+0

@Sam Tôi hoàn toàn đồng ý, do đó thấy câu trả lời khác của tôi (được chấp nhận). Tuy nhiên, tôi tin rằng điều này * là * lý do ban đầu tại sao chúng không tồn tại trong C#. Câu hỏi này thực sự cũ, các câu trả lời được viết trước khi Stack Overflow thực thi các quy tắc nghiêm ngặt hơn về các câu trả lời và trước khi các nhận xét được thực hiện - kết quả là toàn bộ chuỗi này đọc nhiều hơn một cuộc thảo luận (mà nó đã được). Lý do duy nhất tôi chưa xóa câu trả lời này là bởi vì nếu không phần còn lại của câu trả lời ở đây trở nên khó hiểu hơn –

2

Cảm ơn Konrad, đó là một phản ứng tốt (+1), nhưng chỉ để mở rộng trên đó.

Hãy giả vờ rằng C# có chức năng xây dựng rõ ràng:

//your example 
var x = new Foo(1); 

//becomes 
var x = Foo.ctor(1); 

//your problem is valid because this would be 
var x = Foo<T>.ctor<int>(1); 
//and T can't be inferred 

Bạn đang hoàn toàn đúng rằng các nhà xây dựng đầu tiên không thể được suy ra.

Bây giờ chúng ta hãy quay trở lại lớp

class Foo<T> 
{ 
    //<T> can't mean anything else in this context 
    public Foo(T x) { } 
} 

//this would now throw an exception unless the 
//typeparam matches the parameter 
var x = Foo<int>.ctor(1); 

//so why wouldn't this work? 
var x = Foo.ctor(1); 

Tất nhiên, nếu tôi thêm constructor của bạn trở lại (với loại thay thế của nó), chúng tôi có một cuộc gọi rõ ràng - chính xác như nếu một phương pháp quá tải bình thường không thể được giải quyết.

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