Những người quen thuộc với lịch sử đã biết rằng C # và .NET framework khởi đầu về cơ bản là "Delphi viết lại để cảm thấy giống như Java", được kiến trúc sư trưởng đằng sau Delphi, Anders Hejlsberg thiết kế. Mọi thứ đã thay đổi khá nhiều kể từ đó, nhưng ban đầu về những điểm tương đồng rõ ràng đến mức thậm chí còn có một số suy đoán nghiêm trọng rằng .NET thực sự là sản phẩm ban đầu của Borland.
Nhưng gần đây tôi đã xem xét một số công cụ .NET và một trong những tính năng thú vị và hữu ích nhất từ Delphi dường như bị thiếu hoàn toàn: khái niệm các lớp như một kiểu dữ liệu hạng nhất. Đối với những người không quen thuộc với nó, loại TClass
đại diện cho một tham chiếu đến một lớp, tương tự như Type
loại trong .NET. Nhưng trong đó .NET sử dụng Type
để phản chiếu, Delphi sử dụng TClass
như một phần tích hợp rất quan trọng của ngôn ngữ. Nó cho phép các thành ngữ hữu ích khác nhau đơn giản là không tồn tại và không tồn tại mà không có nó, chẳng hạn như các biến kiểu con lớp và phương thức lớp ảo.
Mỗi ngôn ngữ OO đều có các phương thức ảo, trong đó các lớp khác nhau thực hiện cùng một khái niệm cơ bản của một phương thức theo các cách khác nhau và sau đó phương thức đúng được gọi trong thời gian chạy dựa trên loại thực tế của đối tượng mà nó được gọi. Delphi mở rộng khái niệm này cho các lớp: nếu bạn có một tham chiếu TClass được định nghĩa là một kiểu con lớp cụ thể (nghĩa class of TMyClass
là biến đó có thể chấp nhận bất kỳ tham chiếu lớp nào kế thừa từ TMyClass
, nhưng không phải bất cứ thứ gì bên ngoài quyền thừa kế ) có các phương thức ảo phạm vi lớp được đính kèm nó, chúng có thể được gọi mà không cần một thể hiện bằng cách sử dụng kiểu thực tế của lớp. Áp dụng mô hình này cho các nhà xây dựng làm cho việc triển khai Factory trở nên tầm thường, chẳng hạn.
Dường như không có gì tương đương trong .NET. Với sự hữu ích như các tham chiếu lớp (và đặc biệt là các hàm tạo ảo và các phương thức lớp ảo khác!), Có ai nói gì về lý do tại sao chúng bị bỏ đi không?
Ví dụ cụ thể
Hình thức khử lưu huỳnh
Delphi VCL lưu các biểu mẫu ở DFM
định dạng, DSL để mô tả phân cấp thành phần. Khi trình đọc biểu mẫu phân tích dữ liệu DFM, nó sẽ chạy trên các đối tượng được mô tả như sau:
object Name: ClassName
property = value
property = value
...
object SubObjectName: ClassName
...
end
end
Điều thú vị ở đây là ClassName
một phần. Mỗi lớp thành phần đăng ký TClass
với hệ thống truyền phát thành phần tại initialization
thời điểm (nghĩ rằng các hàm tạo tĩnh, chỉ khác nhau một chút, được đảm bảo xảy ra ngay khi khởi động.) Điều này đăng ký mỗi lớp trong một chuỗi -> hàm băm TClass với tên lớp là khóa.
Mỗi thành phần xuất phát từ TComponent
, có một hàm tạo ảo lấy một đối số duy nhất , Owner: TComponent
. Bất kỳ thành phần nào cũng có thể ghi đè lên hàm tạo này để cung cấp cho việc khởi tạo riêng của nó. Khi trình đọc DFM đọc một tên lớp, nó sẽ tìm tên trong hàm băm đã nói ở trên và lấy tham chiếu lớp tương ứng (hoặc đưa ra một ngoại lệ nếu nó không có ở đó), sau đó gọi hàm tạo TComponent ảo trên đó, được biết là tốt bởi vì hàm đăng ký lấy tham chiếu lớp được yêu cầu để xuống từ TComponent và bạn kết thúc với một đối tượng thuộc loại thích hợp.
Thiếu điều này, tương đương WinForms là ... à ... một mớ hỗn độn lớn để nói thẳng ra, đòi hỏi bất kỳ ngôn ngữ .NET mới nào phải thực hiện lại hoàn toàn việc xê-ri hóa hình thức của chính nó. Điều này hơi gây sốc khi bạn nghĩ về nó; vì toàn bộ quan điểm của việc có CLR là cho phép nhiều ngôn ngữ sử dụng cùng một cơ sở hạ tầng cơ bản, nên một hệ thống kiểu DFM sẽ có ý nghĩa hoàn hảo.
Khả năng mở rộng
Một lớp trình quản lý hình ảnh mà tôi đã viết có thể được cung cấp một nguồn dữ liệu (chẳng hạn như đường dẫn đến tệp hình ảnh của bạn) và sau đó tự động tải các đối tượng hình ảnh mới nếu bạn cố truy xuất một tên không có trong bộ sưu tập nhưng có sẵn trong nguồn dữ liệu. Nó có một biến lớp được gõ là class of
lớp hình ảnh cơ sở, đại diện cho lớp của bất kỳ đối tượng mới nào sẽ được tạo. Nó đi kèm với một mặc định, nhưng có một số điểm, khi tạo hình ảnh mới với mục đích đặc biệt, rằng hình ảnh nên được thiết lập theo những cách khác nhau. (Tạo kênh không có kênh alpha, truy xuất siêu dữ liệu đặc biệt từ tệp PNG để chỉ định kích thước sprite, v.v.)
Điều này có thể được thực hiện bằng cách viết một lượng lớn mã cấu hình và chuyển các tùy chọn đặc biệt cho tất cả các phương thức có thể tạo ra một đối tượng mới ... hoặc bạn chỉ có thể tạo một lớp con của lớp hình ảnh cơ sở ghi đè lên một phương thức ảo trong đó khía cạnh trong câu hỏi được cấu hình, và sau đó sử dụng khối try / cuối cùng để thay thế tạm thời thuộc tính "lớp mặc định" khi cần và sau đó khôi phục nó. Làm điều đó với các biến tham chiếu lớp đơn giản hơn nhiều và không phải là điều có thể được thực hiện với generic.
TClass
là hữu ích, với một số mã mẫu? Trong nghiên cứu về internet của tôi TClass
, tôi thấy rằng nó TClass
có thể được truyền qua như một tham số. Điều này được thực hiện trong .NET bằng Generics. Các phương thức Factory được đánh dấu đơn giản static
bằng .NET và không yêu cầu một thể hiện lớp để thực thi.
TClass
là một tính năng ngôn ngữ cơ bản yêu cầu hỗ trợ trình biên dịch. Bạn không thể "tự viết" mà không viết ngôn ngữ của riêng mình và đối với .NET thậm chí điều đó là không đủ vì mô hình đối tượng được xác định bởi CLR, không phải bởi các ngôn ngữ riêng lẻ. Đó là thứ gì đó thực sự cần phải là một phần của chính .NET framework, hoặc nó không thể tồn tại.