Trình biên dịch C # phát hiện các loại COM như thế nào?


168

EDIT: Tôi đã viết kết quả lên như một bài đăng trên blog .


Trình biên dịch C # xử lý các loại COM một cách kỳ diệu. Chẳng hạn, câu lệnh này có vẻ bình thường ...

Word.Application app = new Word.Application();

... Cho đến khi bạn nhận ra đó Applicationlà một giao diện. Gọi một nhà xây dựng trên một giao diện? Yoiks! Điều này thực sự được dịch thành một cuộc gọi đến Type.GetTypeFromCLSID()và khác Activator.CreateInstance.

Ngoài ra, trong C # 4, bạn có thể sử dụng các đối refsố không tham chiếu cho các tham số và trình biên dịch chỉ cần thêm một biến cục bộ để chuyển qua tham chiếu, loại bỏ kết quả:

// FileName parameter is *really* a ref parameter
app.ActiveDocument.SaveAs(FileName: "test.doc");

(Vâng, có một loạt các đối số bị thiếu. Các tham số tùy chọn không đẹp sao? :)

Tôi đang cố gắng điều tra hành vi của trình biên dịch và tôi không thể giả mạo phần đầu tiên. Tôi có thể làm phần thứ hai mà không có vấn đề gì:

using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;

[ComImport, GuidAttribute("00012345-0000-0000-0000-000000000011")]
public interface Dummy
{
    void Foo(ref int x);
}

class Test
{
    static void Main()
    {
        Dummy dummy = null;
        dummy.Foo(10);
    }
}

Tôi muốn có thể viết:

Dummy dummy = new Dummy();

Tuy nhiên. Rõ ràng là nó sẽ nổ tung vào thời gian thực hiện, nhưng không sao. Tôi chỉ đang thử nghiệm.

Các thuộc tính khác được trình biên dịch thêm vào cho các PIA COM được liên kết ( CompilerGeneratedTypeIdentifier) dường như không thực hiện trò lừa ... nước sốt ma thuật là gì?


11
Thông số tùy chọn không đẹp sao? IMO, Không, họ không đẹp. Microsoft đang cố gắng khắc phục lỗ hổng trong giao diện Office COM bằng cách thêm sự phình to vào C #.
Mehrdad Afshari

18
@Mehrdad: Tất nhiên các tham số tùy chọn hữu ích ngoài COM. Bạn cần cẩn thận với các giá trị mặc định, nhưng giữa chúng và các đối số được đặt tên, việc xây dựng một loại bất biến có thể sử dụng sẽ dễ dàng hơn rất nhiều.
Jon Skeet

1
Thật. Cụ thể, các tham số được đặt tên có thể được yêu cầu thực tế để xen kẽ với một số môi trường động. Chắc chắn, không còn nghi ngờ gì nữa, đây là một tính năng hữu ích nhưng điều đó không có nghĩa là nó miễn phí. Nó chi phí đơn giản (một mục tiêu thiết kế được nêu rõ ràng). Cá nhân, tôi nghĩ rằng C # là tuyệt vời cho các tính năng mà nhóm đã bỏ đi (nếu không, nó có thể là một bản sao C ++). Đội ngũ C # rất tuyệt nhưng môi trường doanh nghiệp khó có thể không có chính trị. Tôi đoán rằng bản thân anh ta không hài lòng về điều này khi anh ta nói trong bài nói chuyện PDC'08 của mình: "chúng tôi đã mất mười năm để trở lại nơi chúng tôi đang ở."
Mehrdad Afshari

7
Tôi đồng ý rằng nhóm sẽ cần theo dõi chặt chẽ về sự phức tạp. Các công cụ năng động thêm rất nhiều phức tạp cho ít giá trị cho hầu hết các nhà phát triển, nhưng giá trị cao cho một số nhà phát triển.
Jon Skeet

1
Tôi đã thấy các nhà phát triển khung bắt đầu thảo luận về việc sử dụng nó ở nhiều nơi. IMO chỉ là thời gian cho đến khi chúng tôi tìm thấy một cách sử dụng tốt cho dynamic... chúng tôi đã quá quen với việc gõ tĩnh / mạnh để xem tại sao nó lại quan trọng ngoài COM.
chakrit

Câu trả lời:


145

Tôi không phải là một chuyên gia về vấn đề này, nhưng gần đây tôi đã vấp phải điều tôi nghĩ bạn muốn: lớp thuộc tính CoClass .

[System.Runtime.InteropServices.CoClass(typeof(Test))]
public interface Dummy { }

Một coclass cung cấp (các) triển khai cụ thể của một hoặc nhiều giao diện. Trong COM, các triển khai cụ thể như vậy có thể được viết bằng bất kỳ ngôn ngữ lập trình nào hỗ trợ phát triển thành phần COM, ví dụ Delphi, C ++, Visual Basic, v.v.

Xem câu trả lời của tôi cho một câu hỏi tương tự về Microsoft Speech API , nơi bạn có thể "khởi tạo" giao diện SpVoice(nhưng thực sự, bạn đang bắt đầu SPVoiceClass).

[CoClass(typeof(SpVoiceClass))]
public interface SpVoice : ISpeechVoice, _ISpeechVoiceEvents_Event { }

2
Rất thú vị - sẽ thử nó sau. Các loại PIA được liên kết không có CoClass. Có lẽ đó là một cái gì đó để làm với quá trình liên kết - Tôi sẽ xem xét PIA ban đầu ...
Jon Skeet

64
+1 vì tuyệt vời bằng cách viết câu trả lời được chấp nhận khi Eric Lippert và Jon Skeet cũng trả lời;) Không, thực sự, +1 khi đề cập đến CoClass.
OregonGhost

61

Giữa bạn và Michael, bạn gần như đã có những mảnh ghép lại với nhau. Tôi nghĩ rằng đây là cách nó hoạt động. (Tôi đã không viết mã, vì vậy tôi có thể hơi sai khi nói nó, nhưng tôi khá chắc chắn rằng đây là cách nó diễn ra.)

Nếu:

  • bạn là "người mới" trong một loại giao diện và
  • loại giao diện có một coclass đã biết và
  • bạn đang sử dụng tính năng "không pia" cho giao diện này

sau đó mã được tạo dưới dạng (IPIAINTERFACE) Activator.CreateInstance (Type.GetTypeFromClsid (GUID OF COCLASSTYPE))

Nếu:

  • bạn là "người mới" trong một loại giao diện và
  • loại giao diện có một coclass đã biết và
  • bạn KHÔNG sử dụng tính năng "không pia" cho giao diện này

sau đó mã được tạo như thể bạn đã nói "COCLASSTYPE ()" mới.

Jon, cứ tự nhiên làm phiền tôi hoặc Sam nếu bạn có thắc mắc về công cụ này. FYI, Sam là chuyên gia về tính năng này.


36

Được rồi, đây chỉ là để đưa thêm một chút xác thịt vào câu trả lời của Michael (anh ấy hoan nghênh thêm nó vào nếu anh ấy muốn, trong trường hợp đó tôi sẽ xóa cái này).

Nhìn vào PIA ban đầu cho Word.Application, có ba loại liên quan (bỏ qua các sự kiện):

[ComImport, TypeLibType(...), Guid("..."), DefaultMember("Name")]
public interface _Application
{
     ...
}

[ComImport, Guid("..."), CoClass(typeof(ApplicationClass))]
public interface Application : _Application
{
}

[ComImport, ClassInterface(...), ComSourceInterfaces("..."), Guid("..."), 
 TypeLibType((short) 2), DefaultMember("Name")]
public class ApplicationClass : _Application, Application
{
}

Có hai giao diện cho những lý do mà Eric Lippert nói về câu trả lời khác . Và ở đó, như bạn đã nói, là CoClass- cả về mặt lớp và thuộc tính trên Applicationgiao diện.

Bây giờ nếu chúng ta sử dụng liên kết PIA trong C # 4, một số điều này được nhúng vào nhị phân kết quả ... nhưng không phải tất cả. Một ứng dụng chỉ tạo ra một thể hiện Applicationkết thúc với các loại sau:

[ComImport, TypeIdentifier, Guid("..."), CompilerGenerated]
public interface _Application

[ComImport, Guid("..."), CompilerGenerated, TypeIdentifier]
public interface Application : _Application

Không ApplicationClass- có lẽ bởi vì điều đó sẽ được tải động từ loại COM thực tại thời điểm thực hiện.

Một điều thú vị khác là sự khác biệt về mã giữa phiên bản được liên kết và phiên bản không liên kết. Nếu bạn dịch ngược dòng

Word.Application application = new Word.Application();

trong phiên bản được tham chiếu, nó kết thúc là:

Application application = new ApplicationClass();

trong khi đó trong phiên bản được liên kết, nó kết thúc như

Application application = (Application) 
    Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("...")));

Vì vậy, nó trông giống như "thật" PIA cần CoClassthuộc tính, nhưng phiên bản liên kết không bởi vì có không phải là một CoClasstrình biên dịch có thể thực sự tham khảo. Nó phải làm điều đó một cách năng động.

Tôi có thể thử giả mạo giao diện COM bằng thông tin này và xem liệu tôi có thể có được trình biên dịch để liên kết nó không ...


27

Chỉ cần thêm một chút xác nhận vào câu trả lời của Michael:

Đoạn mã sau biên dịch và chạy:

public class Program
{
    public class Foo : IFoo
    {
    }

    [Guid("00000000-0000-0000-0000-000000000000")]
    [CoClass(typeof(Foo))]
    [ComImport]
    public interface IFoo
    {
    }

    static void Main(string[] args)
    {
        IFoo foo = new IFoo();
    }
}

Bạn cần cả ComImportAttributeGuidAttributecho nó hoạt động.

Cũng lưu ý thông tin khi bạn di chuột qua new IFoo(): Intellisense chọn đúng thông tin: Nice!


cảm ơn, tôi đã thử nhưng tôi đã thiếu thuộc tính ComImport , nhưng khi tôi đi mã nguồn tôi đang làm việc bằng cách sử dụng F12 chỉ hiển thị CoClassGuid , tại sao vậy?
Ehsan Sajjad
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.