Подтвердить что ты не робот

Почему тип System.__ ComObject претендует (иногда) публично, когда это не так?

Просто странность, которую я обнаружил, когда я размышлял над всеми типами, чтобы проверить что-то еще из любопытства.

Почему класс System.__ComObject сборки mscorlib.dll (иногда?) утверждает, что он является общедоступным, когда на самом деле он выглядит непубличным? Если я запустил следующий код в простом консольном приложении С#:

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

вывод кажется противоречивым. Не вложенный тип (t.IsNested is false) должен давать одинаковое значение истинности для IsPublic и IsVisible. Когда я смотрю на сборку с IL DASM, я вижу:

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

который, по моему мнению, очень похож на непубличный класс, что соответствует коду С# ниже:

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

Когда я сравниваю с другим типом с похожим именем, System.__Canon и аналогичными IL-модификаторами, как IsPublic, так и IsVisible возвращает false, как ожидалось.

Кто-нибудь знает, почему (и когда) Type.GetType("System.__ComObject").IsPublic дает true?

4b9b3361

Ответ 1

Монообработка __ComObject может дать некоторые подсказки. Он действительно объявлен как внутренний, но в комментариях говорится: "У него нет публичных методов, его функциональность отображается через System.Runtime.InteropServices.Marshal". Я не впал в Marshal, но я бы предположил, что он отвечает за реализацию GetType(), поэтому он также может настроить свойство IsPublic.

По моему опыту Type.GetType("System.__ComObject").IsPublic всегда true. Что касается GetType("System.Net.Mail.MSAdminBase"), я считаю, что это класс COM, открытый через настроенную первичную сборку взаимодействия, где видимость типа может быть явно контролирована (хотя это только мое мышление, никаких исследований не было сделано).

[ОБНОВЛЕНИЕ]

У меня есть последний исходный код Framework и нашел, что я ошибался в своем предположении, что настройка свойства IsPublic для __ComObject Тип выполняется с помощью Marshal. Собственно, это делается неуправляемым кодом. Object.GetType() определяется внутри Object.cs следующим образом:

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

Неуправляемый исходный код для его реализации в .NET 4.x недоступен, но это доступно для .NET 2.0. Там отличный ответ о реализации Object.GetType в .NET 2.0. Я бы просто добавил, IsPublic определяется интерфейсом System.Runtime.InteropServices._Type, из которого System.Type происходит и может быть переопределено любым из классов System.Type -descendent. По-видимому, реализация такого класса возвращается Object.GetType, и это происходит внутри ObjectNative::GetClass (sscli20\clr\src\vm\comobject.cpp), как показано в ответе:

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

Я подтверждаю, что поведение IsPublic зависит от версии Framework. Я попробовал следующий PowerShell script в разных виртуальных машинах:

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

Вывод:

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

По-видимому, он изменился с False на true с .NET 2.0. Я согласен, что true не соответствует объявлению __ComObject (internal class __ComObject ...). Я лично не вижу причин для таких изменений, потому что единственный способ получить экземпляр __ComObject - через interop.