In IMetadataImport or MonoCecil, how can I find out out if a method in an internal class is accessible from other assembiles?

StackOverflow https://stackoverflow.com/questions/7538689

Question

One of the cases where a public method of an internal class might be accessible from outside the assembly is if the method implements interface methods or overrides virtual methods that are defined in a public base class.

Using IMetadataImport, how can find out if this is the case for a specific mdMethodDef?

Update: I'd also like to know how to do this in Mono.Cecil, as that might help me figure out how to do it in IMetaDataImport.

Was it helpful?

Solution

If I take this C# sample:

public interface ITest
{
    void DoSomething();
}

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

Here, the Test class successfully implements the ITest interface, as defined in C# specification (for example 13.4.2 Interface mapping)

If you examine the result of this code in the compiled assembly (using a tool such as .NET Reflector or ILDASM), you will see this:

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

And... yes...there is nothing here in the assembly metadata that will relate the DoSomething method in Test to the DoSomething method in ITest.

In VB.NET, it's different, you will need to add an Implements keyword to make sure it compiles:

Public Interface ITest

    Sub DoSomething()

End Interface


Public Class Test
    Implements ITest


    Public Sub DoSomething() Implements ITest.DoSomething

    End Sub
End Class

As you see, with VB.NET, you need to explicitely relate the method in the class with the method in the interface, and if you analyse what IL has been created in the assembly in the VB.NET case, you'll find this:

.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 
}

So, with a VB-compiled assembly, the information is there, with a C#-compile assembly, it's not. It depends on the language. The CLR engine will in fact to the mapping at runtime.

If you can inject the assemblies in your process, this code can help you determine interface mapping:

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

But if you need to determine this only looking at metadata, you'll have to write that code yourself. It's not that easy, especially with generics. Also don't forget in C#, a public method can implicitely implement multiple interfaces.

A link that can help: Mono.Cecil something like Type.GetInterfaceMap?

OTHER TIPS

Here's a bit of help wrt Cecil - it does not cover 100% of your question but it may get you close enough as-is or with a bit of additional work.

Many of Gendarme rules have to check methods (or types, fields) visibility so an extension method, IsVisible, was created to deal with most of required checks. And by most I mean there's one thing that is not (yet) implemented is support for the [InternalVisibleTo] attribute.

For methods looks in MethodRocks.cs, other files contains IsVisible extension methods for TypeDefinition and FieldDefinition and a lot of other extensions method you can find useful when working with Cecil.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top