2013-08-06 35 views
20

Chỉ là một điều kỳ quặc tôi tình cờ phát hiện ra khi tôi đang phản ánh trên tất cả các loại để kiểm tra cái gì khác ngoài tò mò.Tại sao loại System .__ ComObject tuyên bố (đôi khi) được công khai khi nó không được?

Tại sao lớp học System.__ComObject của hội đồng mscorlib.dll (đôi khi?) Tuyên bố là công khai khi trên thực tế nó có vẻ không công khai? Nếu tôi chạy mã sau trong ứng dụng giao diện điều khiển C# đơn giản:

var t = Type.GetType("System.__ComObject"); 
Console.WriteLine(t.IsPublic); // "True" ?! 
Console.WriteLine(t.IsVisible); // "False" 

kết quả đầu ra có vẻ mâu thuẫn. Loại không lồng nhau (t.IsNested là sai) phải cung cấp cùng một giá trị thật cho IsPublicIsVisible. Khi tôi nhìn vào lắp ráp với IL DASM tôi thấy:

.class private auto ansi beforefieldinit System.__ComObject 
     extends System.MarshalByRefObject 
{ 
} // end of class System.__ComObject 

đó, với tôi, trông rất giống một tổ chức phi công lớp , một cái gì đó sẽ tương ứng với mã # C dưới đây:

namespace System 
{ 
    // not public 
    internal class __ComObject : MarshalByRefObject 
    { 
     ... 
    } 
} 

Khi tôi so sánh với loại khác có tên tương tự, System.__Canon và các biến tố IL tương tự, cả hai IsPublicIsVisible trả về false như mong đợi.

Có ai biết tại sao (và khi nào) Type.GetType("System.__ComObject").IsPublic cho đúng không?

+1

Hệ thống .__ ComObject và System .__ Canon là rất khác nhau - đầu tiên là đối tượng COM (IsCOMObject == true) - đó là lý do tại sao tôi nghĩ nó là Công cộng và thứ hai thì không. –

+1

@Mihail Nếu tôi sử dụng 'var t = typeof (Uri) .Assembly.GetType (" System.Net.Mail.MSAdminBase ");' Tôi có một kiểu 't' khác cũng' IsCOMObject', nhưng 'IsNotPublic'. Vì vậy, đó có vẻ là một "counterexample" để giải thích rằng, trừ khi đây là một cái gì đó mà phụ thuộc vào lắp ráp ('System.Net.Mail.MSAdminBase' là trong một hội đồng, so với' System .__ ComObject'). –

+1

Tất cả những gì tôi có thể tìm ra là, đây có thể là một khiếm khuyết! Tôi đã xem qua một số nội dung tương tự, có thể các bạn cũng đã gặp phải điều tương tự. Theo dõi [link] (http://microsoft.public.dotnet.framework.interop.narkive.com/06Y4MWuX/reflection-messing-up-the-type-hierarchy) – Nilesh

Trả lời

10

Mono's implementation trong số __ComObject có thể cung cấp một số manh mối. Nó thực sự được khai báo là nội bộ, nhưng các nhận xét nói "Nó không có phương pháp công khai, chức năng của nó được tiếp xúc với máng System.Runtime.InteropServices.Marshal". Tôi chưa đào vào Marshal, nhưng tôi cho rằng nó chịu trách nhiệm thực hiện GetType(), vì vậy nó cũng có thể tùy chỉnh thuộc tính IsPublic.

Theo kinh nghiệm của tôi, Type.GetType("System.__ComObject").IsPublic luôn là true. Về GetType("System.Net.Mail.MSAdminBase"), tôi tin rằng đó là một lớp COM tiếp xúc thông qua một customized primary interop assembly, nơi tầm nhìn của một loại có thể được kiểm soát một cách rõ ràng (mặc dù nó chỉ là suy nghĩ của tôi, không có nghiên cứu đã được thực hiện).

[UPDATE]

tôi đã có latest Framework source code và thấy tôi đã sai về giả định của tôi rằng tuỳ biến của IsPublic tài sản cho __ComObject Loại được thực hiện bằng Marshal. Trên thực tế, nó được thực hiện bởi mã không được quản lý. Object.GetType() được định nghĩa bên trong Object.cs như thế này:

[MethodImplAttribute(MethodImplOptions.InternalCall)] 
public extern Type GetType(); 

Các mã nguồn không được quản lý để thực hiện nó trong .NET 4.x không có sẵn, nhưng nó là available cho .NET 2.0. Có một excellent answer về việc thực hiện Object.GetType trong .NET 2.0. Tôi chỉ cần thêm, IsPublic được xác định bởi giao diện System.Runtime.InteropServices._TypeSystem.Type có nguồn gốc từ và có thể bị ghi đè bởi bất kỳ lớp học nào trong số System.Type. Rõ ràng, việc triển khai lớp đó được trả về bởi Object.GetType và điều đó xảy ra bên trong ObjectNative::GetClass (sscli20 \ clr \ src \ vm \ comobject.cpp), như trong the answer:

if (!objRef->IsThunking()) 
    refType = typeHandle.GetManagedClassObject(); 
else 
    refType = CRemotingServices::GetClass(objRef); 

Tôi xác nhận rằng hành vi của IsPublic phụ thuộc vào phiên bản Framework. Tôi đã thử các kịch bản PowerShell sau trong máy ảo khác nhau:

Write-Host ([System.Environment]::Version) ([Type]::GetType("System.__ComObject")).IsPublic 

Đầu ra là:

2.0.50727.3643 False (WinXP) 
4.0.30319.18052 True (Win7) 
4.0.30319.19079 True (Win8) 

Rõ ràng, nó đã thay đổi False-True kể từ NET 2.0. Tôi đồng ý rằng True không phù hợp với tuyên bố của __ComObject (internal class __ComObject ...). Cá nhân tôi không thấy lý do nào cho sự thay đổi đó, bởi vì cách duy nhất để có được một thể hiện của __ComObject là thông qua interop.

+0

Tôi chưa thử nghiệm điều này ở Mono. Tôi không tìm thấy bất cứ điều gì trong mã nguồn bạn liên kết mà dường như có liên quan, với tôi. Tôi không chắc bạn muốn nói gì về 'GetType' và' IsPublic'. Sau này là một thuộc tính cá thể không (mặc dù giao diện thực hiện) trên lớp 'System.Type' trừu tượng, vì vậy tôi cần giải thích về cách' __ComObject' hoặc 'Marshal'" có thể tùy chỉnh "nó (từ của bạn). Lý do tại sao tôi nói "(đôi khi)" trong câu hỏi, là tôi đã thử nghiệm điều này trong PowerShell trên hai máy khác nhau, với một máy xử lý (thông qua PowerShell) '__ComObject' là không công khai, rõ ràng. –

+1

Tôi đã thử những điều sau đây với PowerShell: 'Write-Host ([System.Environment] :: Version) ([Type] :: GetType (" System .__ ComObject ")). IsPublic', đầu ra:' 4.0.30319.19079 True' (Win8), '4.0.30319.18052 True' (Win7),' 2.0.50727.3643 Sai' (WinXP). Rõ ràng, kết quả của 'IsPublic' cho' __ComObject' phụ thuộc vào phiên bản khung công tác. Tôi sẽ thực hiện một số nghiên cứu và cung cấp giải thích về 'Nguyên soái' mà bạn yêu cầu. – Noseratio

+0

Xin lỗi, tôi không chắc chắn ý của bạn là gì khi nói rằng ('IsPublic') _ là một thuộc tính cá thể không phải là ảo (mặc dù giao diện thực hiện) trên trừu tượng' System.Type'. Thuộc tính được định nghĩa trong giao diện 'System.Runtime.InteropServices._Type', vì vậy nó là ảo theo định nghĩa và có thể được ghi đè bởi bất kỳ lớp dẫn xuất nào, giống như' IsCOMObject'. 'System.Type' không triển khai' IsPublic', nhưng một số lớp dẫn xuất của nó làm, ví dụ: 'System.RuntimeType'. Tôi thừa nhận tôi đã sai giả định tùy biến được thực hiện bởi 'Marshal' mặc dù, nó thực sự được thực hiện với mã không được quản lý. Tôi đã cập nhật câu trả lời của mình với nhiều chi tiết hơn. – Noseratio

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