2009-07-07 38 views
160

EDIT: Tôi đã viết kết quả dưới dạng blog post.Trình biên dịch C# phát hiện các kiểu COM như thế nào?


Trình biên dịch C# xử lý các loại COM hơi kỳ diệu. Ví dụ: tuyên bố này có vẻ bình thường ...

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

... cho đến khi bạn nhận ra rằng Application là một giao diện. Gọi một hàm tạo trên một giao diện? Yoiks! Điều này thực sự được dịch sang một cuộc gọi đến Type.GetTypeFromCLSID() và một cuộc gọi khác đến Activator.CreateInstance.

Thêm vào đó, trong C# 4, bạn có thể sử dụng lập luận phi ref cho ref thông số, và trình biên dịch chỉ cần thêm một biến địa phương đi ngang qua tham khảo, loại bỏ các kết quả:

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

(Yeah, có Không phải là tham số tùy chọn tốt đẹp? :)

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 giả mạo phần đầu tiên. Tôi có thể làm phần thứ hai với không có vấn đề:

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

[ComImport, GuidAttribute("00-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(); 

mặc dù. Rõ ràng là nó sẽ nổ tung tại thời điểm 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 thêm bởi trình biên dịch cho các COM PIA được liên kết (CompilerGeneratedTypeIdentifier) dường như không thực hiện các mẹo ... nước sốt ma thuật là gì?

+0

Bạn đang đi trước tôi về công cụ này (hầu hết các công cụ), nhưng chỉ để clairification, nó có vẻ như những gì bạn đang sau là chức năng tiêm phụ thuộc với một cú pháp chuẩn hóa hơn - đó sẽ là chính xác? –

+11

Thông số tùy chọn không đẹp? IMO, Không họ không đẹp. Microsoft đang cố sửa lỗ hổng trong các giao diện Office COM bằng cách thêm bloat vào C#. –

+0

Câu hỏi hay (+1). Tôi đã nhận thấy điều tương tự về việc gọi một hàm tạo trên một giao diện. Nó trông khủng khiếp trong mã vì nó sẽ thực sự gây nhầm lẫn cho bất kỳ nhà phát triển không quen thuộc với những gì đang xảy ra. Tôi luôn tự hỏi điều gì đang diễn ra đằng sau hậu trường để làm cho nó hoạt động. Có vẻ như tôi sẽ mua sách mới của bạn ;-) –

Trả lời

138

Không có nghĩa là tôi là một chuyên gia về điều này, nhưng tôi tình cờ gần đây về những gì tôi nghĩ rằng bạn muốn: lớp thuộc tính CoClass.

nguồn cung cấp
[System.Runtime.InteropServices.CoClass(typeof(Test))] 
public interface Dummy { } 

Một coclass bê tông thực hiện (s) của một hoặc nhiều giao diện. Trong COM, việc triển khai cụ thể 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, vv

Xem my answer to a similar question about the Microsoft Speech API, nơi bạn có thể "nhanh chóng" giao diện SpVoice (nhưng thực sự, bạn đang instantiating SPVoiceClass).

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

Rất thú vị - sẽ thử 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ẽ có một cái nhìn trong PIA ban đầu ... –

+64

1 cho là 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 để đề cập đến CoClass. – OregonGhost

60

Giữa bạn và Michael bạn gần như đã ghép các mảnh ghép lại với nhau. Tôi nghĩ đâ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-nêu rõ nó, nhưng tôi khá chắc chắn đây là cách nó đi.)

Nếu:

  • bạn là "mới" ing một kiểu giao diện, và
  • kiểu giao diện có một coclass được biết đến, và
  • bạn đang sử dụng "không pia" tính năng cho điều này giao diện

sau đó mã được tạo ra như (IPIAINTERFACE) Activator.CreateInstance (Type.GetTypeFromClsid (GUID HÀNH COCLASSTYPE))

Nếu:

  • bạn là "mới" ing một kiểu giao diện, và
  • kiểu giao diện có một coclass được biết đến, và
  • bạn không sử dụng "không pia" tính năng cho giao diện này

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

Jon, vui lòng báo lỗi cho tôi hoặc Sam trực tiếp nếu bạn có câu hỏi về nội dung này. FYI, Sam là chuyên gia về tính năng này.

35

Được rồi, đây chỉ là để thêm một chút thịt vào câu trả lời của Michael (anh ấy được chào đón để thêm nó vào nếu anh ta muốn, trong trường hợp này tôi sẽ loại bỏ 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 vì những lý do mà Eric Lippert nói về trong another answer. Và ở đó, như bạn đã nói, là CoClass - cả về chính lớp và thuộc tính trên giao diện Application.

Bây giờ nếu chúng tôi sử dụng PIA liên kết trong C# 4, một số của điều này được nhúng vào kết quả nhị phân ... nhưng không phải tất cả. Một ứng dụng mà chỉ tạo ra một thể hiện của Application kế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ẽ vì điều đó sẽ được nạp tự động từ thực loại COM tại thời gian thực hiện.

Một điều thú vị khác là mã giữa phiên bản được liên kết và phiên bản không được 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 tham chiếu nó kết thúc như:

Application application = new ApplicationClass(); 

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

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

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

tôi có thể cố gắng để giả lập một giao diện COM sử dụng thông tin này và xem liệu tôi có thể nhận được biên dịch để liên kết nó ...

26

Chỉ cần thêm một chút để xác nhận Michael trả lời:

Các 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ả ComImportAttributeGuidAttribute cho nó để làm việc.

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

+0

cảm ơn, tôi đã cố gắng nhưng tôi đã mất ** ComImport ** thuộc tính, nhưng khi tôi đi i mã nguồn tôi đã làm việc bằng cách sử dụng F12 chỉ hiển thị ** CoClass ** và ** Guid **, tại sao vậy? –

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