Tốt hơn nên viết thư viện .NET của bạn với các giới hạn COM trong tâm trí hoặc tách thư viện .NET của bạn khỏi Interop?


9

Tôi đã xem qua bài viết thú vị này: Làm thế nào tôi yêu thích khả năng tương tác của COM trên CodeProject, điều đó khiến tôi suy nghĩ ...

Tác giả lập luận rằng họ không muốn bất kỳ COM-ities nào trong thư viện .NET của họ vì nó làm mất đi vẻ đẹp của thư viện .NET của họ. Thay vào đó, họ thà viết một thư viện Interop riêng để lộ thư viện .NET của họ thành COM. Thư viện Interop này sẽ xử lý thực tế là COM không hỗ trợ Trình xây dựng với Tham số, Phương thức quá tải, Generics, Kế thừa, Phương thức tĩnh, v.v.

Và trong khi tôi nghĩ rằng nó rất mới lạ, không phải nó chỉ tuân theo dự án sao?

  • Bây giờ bạn cần đơn vị kiểm tra thư viện .NET VÀ thư viện Interop.
  • Bây giờ bạn cần dành thời gian để tìm ra cách làm việc xung quanh thư viện .NET đẹp của bạn và đưa nó ra COM.
  • Bạn cần, hiệu quả, tăng gấp đôi hoặc gấp ba số lượng lớp học của bạn.

Tôi chắc chắn có thể hiểu nếu bạn cần thư viện của mình để hỗ trợ cả COM và không COM. Tuy nhiên, nếu bạn chỉ có ý định sử dụng COM thì kiểu thiết kế này có mang lại lợi ích gì mà tôi không thấy không? Bạn chỉ đạt được những lợi ích của ngôn ngữ C #?

Hoặc, nó có làm cho phiên bản thư viện của bạn dễ dàng hơn bằng cách cung cấp cho bạn một trình bao bọc không? Nó có làm cho Bài kiểm tra đơn vị của bạn chạy nhanh hơn bằng cách không yêu cầu sử dụng COM không?


2
Ý bạn là, bên cạnh việc có thể sử dụng các công cụ hữu ích để làm cho mã thực sự tốt hơn / sạch hơn? Và cung cấp một đường dẫn di chuyển rõ ràng cho công cụ COM (có lẽ là di sản) đó?
Telastyn

3
Điều này giống như một mô hình mặt tiền viết lớn trên toàn bộ không gian tên. Tôi nghĩ thật thông minh khi tổ chức nó như thế này nếu bạn muốn sử dụng các tính năng .NET nhưng thực sự cần OLE Tự động hóa. Các trình bao bọc COM của bạn về cơ bản sẽ là để chuyển đổi các thành ngữ hiện đại (bất biến? Chung chung?) Thành các đối tượng COM cũ hơn với các hàm tạo không tham số, các đối tượng có thể thay đổi nhiều và SAFEARRAY cho danh sách chung của bạn. Nếu bạn đang hỗ trợ các thành phần .NET khác hoặc hoàn toàn yêu thích các kiểu mới, điều này sẽ có ý nghĩa. Nếu bạn CHỈ hỗ trợ COM, thì tại sao không viết toàn bộ trong VB6 (32 bit) và chỉ giữ một thành ngữ?
Mike hỗ trợ Monica

3
@MasonWheeler: Nó không được dùng theo cùng một cách mà tất cả các phần mềm cũ hơn 6 tháng là "di sản", phải không?
whatsisname

2
@MasonWheeler COM không thể được khấu hao cho dù có bao nhiêu người (bao gồm một số nhóm trong Microsoft) muốn điều đó bởi vì đây vẫn là lựa chọn tốt nhất để kiểm soát mọi thứ ngoài quy trình.
Mike hỗ trợ Monica

2
@Mike, tôi thực sự đang xem xét chuyển một dự án VB6 sang C # .NET. Các API hướng tới người dùng mà chúng tôi sử dụng rất đơn giản, tuy nhiên, mã phía sau hậu trường không thể duy trì được. Tôi hy vọng sẽ triển khai phần lớn thư viện trong C # .NET và cung cấp Mặt tiền Interop cung cấp các API đơn giản tương tác với các lớp khác nhau.
robodude666

Câu trả lời:


7

Tuy nhiên, nếu bạn chỉ có ý định sử dụng COM thì kiểu thiết kế này có mang lại lợi ích gì mà tôi không thấy không?

Đoạn này của câu hỏi của bạn là những phần quan trọng nhất quyết định thiết kế của bạn ở đây, và câu trả lời là (như mọi khi) nó phụ thuộc .

Nếu bạn chỉ có ý định sử dụng thư viện thông qua COM Interop, thì bạn nên thiết kế toàn bộ hệ thống với ý tưởng này. Không có lý do để tăng gấp ba số lượng dòng. Càng nhiều LoC trong hệ thống, nó sẽ càng có nhiều khiếm khuyết. Do đó, bạn nên thiết kế hệ thống của mình để chỉ sử dụng chức năng tương thích COM.

Tuy nhiên , tôi không thể nghĩ ra một lý do chính đáng để hạn chế việc sử dụng thư viện .Net vào COM. Tại sao bạn không muốn có thể sử dụng cụm trong mã .Net khác? Nó có ý nghĩa rất nhỏ để giới hạn bản thân theo cách này.

Tôi có một số kinh nghiệm với điều này, vì vậy tôi sẽ chia sẻ cách tôi đã xử lý nó. Nó chắc chắn không lý tưởng. Tôi đã thực hiện một số đánh đổi. Tôi chỉ sử dụng một mặt tiền cho các lớp COM (giao diện thực sự) không tương thích với các thành ngữ .Net mới hơn, nếu không, tôi trực tiếp đưa giao diện .Net sang COM. Điều này về cơ bản có nghĩa là tôi sử dụng một mặt tiền cho bất kỳ giao diện nào sử dụng generic. Generics là điều duy nhất tôi đi qua chỉ đơn giản là không tương thích. Thật không may, điều này có nghĩa là một mặt tiền cho bất cứ điều gì trả lại một IEnumerable<T>, khá phổ biến.

Tuy nhiên, điều này gần như không tệ như vậy, vì lớp mặt tiền của bạn kế thừa từ lớp .Net của bạn và thực hiện giao diện Interop cụ thể. Một cái gì đó như thế này.

namespace Company.Product.Feature
{
    public class MyClass : INetInterface 
    {
        // lots of code
    }
}

namespace Company.Product.Interop
{
    public class MyClass : Feature.MyClass, IComInterface
    {
        // over ride only the  incompatible properties/methods
    }
}

Điều này giữ cho mã trùng lặp của bạn ở mức tối thiểu tuyệt đối và bảo vệ giao diện COM của bạn khỏi những thay đổi "không chủ ý". Khi lớp lõi / giao diện cốt lõi của bạn thay đổi, lớp bộ điều hợp của bạn phải vượt qua nhiều phương thức hơn (hoặc phá vỡ giao diện và tăng số phiên bản chính). Mặt khác, không phải tất cả mã Interop của bạn được lưu trữ trong Interopkhông gian tên, điều này có thể dẫn đến một tổ chức tệp khó hiểu. Như tôi đã nói, đó là một sự đánh đổi.

Để có một ví dụ đầy đủ về điều này, bạn có thể duyệt qua các thư mục SourceControlInterop của repo của tôi. ISourceControlProviderGitProvidersẽ được quan tâm đặc biệt.


Cảm ơn bạn đã phản hồi @RubberDuck! Tôi đã chạy qua dự án RubberDuck vài ngày trước; đọc mã rất thú vị. Bạn có thể vượt qua IEnumerableVBA không? Ngoài ra, tại Rubberduck.Interop.GitProvidersao bạn xác định các hàm tạo được tham số hóa nếu COM không hỗ trợ chúng?
robodude666

Có, bạn có thể chuyển IEnumerablequa COM, nhưng nó phải là phiên bản cũ hơn, không chung chung. Đối với các nhà xây dựng, hãy xem SourceControlClassFactory. Về cơ bản, bạn giả mạo nó bằng cách khởi tạo một thể hiện của một lớp không cần tham số cho ctor của nó và sử dụng nó để có quyền truy cập vào các phiên bản mới của các lớp API của bạn.
RubberDuck

Tôi đoán rằng mọi thứ được định nghĩa trong các ComVisible(true)lớp / giao diện của bạn mà COM không hỗ trợ chỉ đơn giản là "bị bỏ qua"? Tôi cũng đoán nếu bạn có một lớp cùng tên được xác định trong nhiều không gian tên bạn sẽ phải cung cấp một duy nhất ProgIdnếu bạn muốn hiển thị nhiều hơn một trong số chúng?
robodude666

Đúng. Điều đó đúng và staticphương pháp bị bỏ qua. Tôi đang cố gắng xem liệu có sẵn tương đương với VB6 không VB_PredeclaredId. Tôi nghĩ rằng thể tạo một thể hiện mặc định.
RubberDuck

7

nó làm mất đi vẻ đẹp của thư viện .NET của họ

Tác giả đó cần một cái tát đánh thức vào mặt. Đối với bất kỳ dự án chuyên nghiệp nào, mục tiêu là tạo ra phần mềm làm việc mà mọi người muốn sử dụng. Bất kỳ loại lý tưởng sai lầm về vẻ đẹp đến sau đó rất lâu. Nếu đó là lý do duy nhất của họ, tác giả đã mất tất cả uy tín.

Có thể đánh dấu các lớp của bạn là có thể nhìn thấy và có thể nói chuyện với mã .NET của bạn thông qua COM là rất hữu ích. Loại bỏ lợi ích to lớn đó cho năng suất làm đẹp là điên rồ.

Tuy nhiên, làm cho mọi thứ hoạt động với COM đòi hỏi một số sự đánh đổi, yêu cầu một nhà xây dựng không có đối số là một trong số đó, và một số nội dung khác mà bạn đã đề cập. Nếu đó là những tính năng bạn không sử dụng, hoặc nó sẽ không làm bạn đau khi không sử dụng chúng, thì có rất nhiều công việc phải được lưu bằng cách sử dụng cùng một lớp cho COM và không com.

Mặt khác, nếu các máy khách COM của bạn mong đợi một giao diện khác biệt đáng kể, có các phụ thuộc hoặc các hạn chế khác gây khó chịu khi xử lý các lớp .NET của bạn hoặc bạn sẽ thay đổi đáng kể các lớp .NET của mình và cần duy trì COM lạc hậu- khả năng tương thích, sau đó bằng mọi cách tạo ra một lớp Interop để thu hẹp khoảng cách đó.

Nhưng đừng nghĩ về "cái đẹp". Có thể hiển thị COM thông qua .NET có nghĩa là để tiết kiệm công việc của bạn. Đừng tạo thêm công việc cho chính mình.


+1. Trong khi tôi yêu vẻ đẹp của các nút đen trên thực tế hộp đen thì quan trọng hơn nhiều.
gbjbaanb

Trên thực tế, người đã giới thiệu thuật ngữ "vẻ đẹp" trong cuộc thảo luận này có thể cần một cú đánh thức, và đó không phải là tác giả của bài báo khác.
Doc Brown

2
Chỉ cần một lưu ý phụ, nếu các nhà xây dựng hiện tại của bạn yêu cầu đối số, tốt nhất là cung cấp một nhà máy lớp cho các thành phần COM của bạn, thay vì thiết kế lại giao diện / API hiện có.
RubberDuck

1
Có thể giới thiệu nhà máy của bạn là một lớp "GlobalMultiUse" không? Vì vậy, bạn có thể làm Set oObject = MyCOMInterop.NewMyClass()mà không cần phải khởi tạo một đối tượng Factory mới?
robodude666

Đó là một câu hỏi hay chết tiệt @ robodude666. Bây giờ bạn đề cập đến nó, tôi hy vọng như vậy.
RubberDuck

3

Chà, công bằng mà nói, tác giả ban đầu của bài báo đó đã không sử dụng từ "vẻ đẹp" ở bất cứ đâu trong bài viết của mình, đó là bạn, có thể gây ấn tượng thiên vị cho những người không dành thời gian để đọc bài viết đó chúng tôi.

Theo như tôi đã hiểu bài viết đó, thư viện .NET đã tồn tại và được viết mà không có COM trong tâm trí - có lẽ bởi vì tại thời điểm thư viện được tạo ra, không có yêu cầu hỗ trợ COM.

Sau đó, yêu cầu bổ sung của COM hỗ trợ đã được giới thiệu. Đối mặt với một tình huống như vậy, bạn có hai lựa chọn:

  • thiết kế lại lib ban đầu để làm cho nó tương thích với COM interop (có nguy cơ phá vỡ mọi thứ)

  • hãy để thư viện làm việc ban đầu chủ yếu, và thay vào đó tạo ra một hội đồng riêng với chức năng của "trình bao bọc" (hoặc "bộ điều hợp")

Tạo các hàm bao hoặc bộ điều hợp là một mẫu thiết kế nổi tiếng (hoặc trong trường hợp này là một mẫu kiến ​​trúc), và những ưu và nhược điểm cũng được biết đến. Một lập luận cho nó là "sự tách biệt mối quan tâm" tốt hơn, và điều đó không liên quan gì đến cái đẹp.

Những lo lắng của bạn

Bây giờ bạn cần đơn vị kiểm tra thư viện .NET VÀ thư viện Interop.

Khi bạn giới thiệu giao diện COM của mình cho thư viện .NET hiện tại bằng cách thiết kế lại, bạn phải kiểm tra giao diện đó. Tất nhiên, việc giới thiệu một bộ điều hợp bằng văn bản có thể cần một số thử nghiệm bổ sung mà giao diện đang hoạt động, nhưng không cần phải sao chép tất cả các thử nghiệm đơn vị về chức năng kinh doanh cốt lõi của lib. Đừng quên nó chỉ là một giao diện khác cho lib.

Bây giờ bạn cần dành thời gian để tìm ra cách làm việc xung quanh thư viện .NET đẹp của bạn và đưa nó ra COM.

Khi bạn phải thiết kế lại thư viện ban đầu, bạn cũng phải tìm ra điều đó, và tôi đoán nó sẽ làm việc nhiều hơn.

Bạn cần, hiệu quả, tăng gấp đôi hoặc gấp ba số lượng lớp học của bạn.

Chỉ dành cho các lớp được hiển thị thông qua giao diện COM công cộng, đây chỉ là một số lượng nhỏ các phần của thư viện gốc.

Nói rằng, đối với một tình huống khác mà bạn đã đề cập, khi bạn biết rằng bạn phải hỗ trợ COM với tư cách là công dân hạng nhất ngay từ đầu, tôi nghĩ bạn đã đúng: nên tiết kiệm rắc rối khi thêm một bộ chuyển đổi lib tách rời và thiết kế .NET lib có hỗ trợ COM trực tiếp.


(+1) Tuy nhiên, "... chỉ là một số lượng nhỏ ... thư viện gốc" đôi khi chỉ đúng. Có rất nhiều loại dự án được thiết kế theo "kiểu thư viện lớp", trong đó một lớp bằng với một mục đích hiển thị công khai và các lớp đó hợp thành để tạo ra chức năng thú vị. Trong trường hợp đó, có thể có ánh xạ một-một giữa số lượng lớp .NET và số lượng lớp xen kẽ COM.
rwong
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.