2011-09-24 5 views
2

Одним из случаев, когда открытый метод внутреннего класса может быть доступен извне сборки, является то, что метод реализует методы интерфейса или переопределяет виртуальные методы, которые определены в общедоступном базовом классе.В IMetadataImport или MonoCecil, как я могу узнать, доступен ли метод во внутреннем классе из других сборок?

Использование IMetadataImport, как узнать, имеет ли это значение конкретный mdMethodDef?

Обновление: Я также хотел бы знать, как это сделать в Mono.Cecil, поскольку это может помочь мне выяснить, как это сделать в IMetaDataImport.

ответ

3

Если я это C# образец:

public interface ITest 
{ 
    void DoSomething(); 
} 

public class Test : ITest 
{ 
    public void DoSomething() 
    { 
    } 
} 

Здесь Test класс успешно реализует интерфейс ITest, как это определено в C# спецификации (например 13.4.2 Interface mapping)

Если проанализировать результат этого кода скомпилированной сборки (с использованием такого инструмента, как .NET Reflector или ILDASM), вы увидите следующее:

.method public hidebysig newslot virtual final instance void DoSomething() cil managed 
{ 
    .maxstack 8 
    L_0000: nop 
    L_0001: ret 
} 

И ... да ... здесь нет ничего в метаданных сборки, которые будут относить метод DoSomething в тесте к методу DoSomething в ITest.

В VB.NET, это разные, вам нужно будет добавить Implements ключевое слово, чтобы убедиться, что она составляет:

Public Interface ITest 

    Sub DoSomething() 

End Interface 


Public Class Test 
    Implements ITest 


    Public Sub DoSomething() Implements ITest.DoSomething 

    End Sub 
End Class 

Как вы видите, с VB.NET, вам необходимо явно связать метод в класс с помощью метода в интерфейсе, и если проанализировать то, что IL был создан в сборке в случае VB.NET, вы найдете это:

.method public newslot virtual final instance void DoSomething() cil managed 
{ 
    .override TestVB.ITest::DoSomething 
    .maxstack 8 
    L_0000: nop 
    L_0001: nop 
    L_0002: ret 
} 

Так, с VB скомпилированные сборки с, информация есть, с C# -компиляционной сборкой, это не так. Это зависит от языка. Механизм CLR на самом деле будет отображаться во время выполнения.

Если вы можете впрыснуть сборки в вашем процессе, этот код может помочь вам определить отображение интерфейса:

InterfaceMapping im = typeof(Test).GetInterfaceMap(typeof(ITest)); 

Но если вам нужно определить это только глядя на метаданные, вы должны написать этот код сам. Это не так просто, особенно с дженериками. Также не забывайте, что в C# публичный метод может вводить несколько интерфейсов.

Ссылка, которая может помочь: Mono.Cecil something like Type.GetInterfaceMap?

+0

Ваше объяснение и код в приведенной ссылке (что привело меня к методу «GetOriginalBaseMethod» Сесила) именно то, что мне нужно. Большое спасибо. –

1

Немного о помощи по Сесилу - он не покрывает 100% вашего вопроса, но он может получить вас достаточно близко as-is или с немного дополнительной работой.

Многие Gendarme правил должно проверить методы (или типов, поля) видимость так что расширения методы, IsVisible, была созданы, чтобы иметь дело с наиболее необходимыми проверками. И по most Я имею в виду, что есть одна вещь, которая еще не реализована - это поддержка атрибута [InternalVisibleTo].

Для методов выглядит в MethodRocks.cs, другие файлы содержат IsVisible методы расширения для TypeDefinition и FieldDefinition и много других расширения методы вы можете найти полезными при работе с Сесиль.

+0

я мог бы что-то не хватает, но мне кажется, что этот код не имеет дело со случаем, я с просьбой о? Возьмем, к примеру, сценарий, когда IsVisible вызывается в MethodRef для 'System.OrdinalComparer.Equals (string, string)', этот метод DeclaringType этого метода (OrdinalComparer) является внутренним, поэтому IsVisible возвращает false, хотя я могу с радостью вызвать этот метод извне mscorlib, если у меня есть ссылка на него как StringComparer (т. е. если я делаю 'StringComparer.Ordinal.Equals (" a "," b ")') –

+0

Нет, что не будет работать * без дополнительной работы * для соответствия всем интерфейсам/базовый класс, который может публиковать его публично. В Gendarme есть аналогичный код (чтобы найти интерфейсы, базовый класс, метод соответствия ...), который можно использовать в качестве строительных блоков, но * как есть *, он охватывает 100% вашего вопроса. – poupou