1

I reflect on an Autodesk assembly and found the following:

enter image description here

Note that for the PressurePipeNetwork class, it is public, and there is a method AddLinePipe which is also a public. However, one of the parameters for AddLinePipe, PressurePartSize is internal.

enter image description here

Usually we will not be able to compile with code like this ( and we will get "Inconsistent Accessibility" sort of compilation error) in .Net. But somehow this assembly got away with it.

And I check already, there is only one PressurePartSize in the assembly.

I'm not too sure when someone said that it cannot be done. Autodesk already did it; I got the assembly!

Not only that, one can somehow use the library in C#, but with the error message

Autodesk.Civil.DatabaseServices.Styles.PressurePartSize is showing error that in accessable due to protection level.

How to do it? I am willing to use any language to achieve this, not just C#. or .Net

Graviton
  • 81,782
  • 146
  • 424
  • 602
  • 1
    I don't know. But there is little suggesting that this library has been written in C#. The developers of that library could have used a different language using a different compiler that is less strict with regard to these things. (Or maybe it was witten in C# some long time ago, using an ancient C# compiler that did not have that kind of accessiblity check yet; i don't really know, i just make that stuff up here as i go. ;-) ) –  May 08 '19 at 10:09
  • You cannot do it. Period. A different question then would be what the decompiled code means, and if the two PressurePartSize types are the same, how they accomplished that, but with todays C# compiler, you cannot do it. – Lasse V. Karlsen May 08 '19 at 10:17
  • 1
    It's worth noting that the sole constructor for `PressurePipeNetwork` is internal. – John Wu May 08 '19 at 10:25
  • @JohnWu, so? The `PressurePipeNetwork` might only be instantiated internally, but then, it can still be accessed and the method be used publicly. What's the big deal? – Graviton May 08 '19 at 10:26
  • Is the *type* with that method public as well? If you have an internal type with a public method, that method is allowed to take internal types as parameters. – Lasse V. Karlsen May 08 '19 at 10:34
  • @LasseVågsætherKarlsen, are you referring to `PressurePipeNetwork`? Yes, it is `public`. – Graviton May 08 '19 at 10:36
  • https://stackoverflow.com/questions/54809792/c-sharp-runtimebinderexception-when-using-dynamic-variable-to-handle-internal-ty - have you read this or tried the techniques listed in the linked question? It doesn't answer your question but it may help you attack it a different way. – mjwills May 08 '19 at 10:36
  • 2
    I also question the validity of this decompilation, it looks like Telerik decompiler is barfing all over this code, are you even sure it is decompiled correctly, the parts that are readable? Of course, the reason it is barfing may of course be that the code isn't valid C# and it tries to shoehorn it into the C# syntax unsuccessfully. – Lasse V. Karlsen May 08 '19 at 10:40
  • 1
    This is not C# code, it was written in C++/CLI. PressurePartSize is likely to be a native C++ class. The C++/CLI compiler emits a metadata definition for such a class but it is not accessible. Not an issue as long as the call is made from C++/CLI code. That this decompiler dies on it is not terribly unusual. Reflector does a somewhat better job on such code, but no .NET decompiler is going to decompile native code. – Hans Passant May 08 '19 at 13:39

2 Answers2

3

This cannot be done in C#. The .NET virtual machine is more lenient than C#, though. There are many features that C# does not expose.

At the IL level you can call non-public methods just fine. You also can do that using runtime code generation using reflection emit. This is very useful for creating fast serializers.

The JIT also is able to compile unverifiable and even incorrect IL. The result is not fully defined.

How was this assembly created? My first thought was that this is the result of an IL linker tool. .NET assemblies can be post-processed to merge or optimize them. This also could be the result of an obfuscation tool (especially the method that cannot be decompiled).

Looks like the tool has a bug because it surely is not intentional to create a public method that is not normally callable.

If you want to experiment with this you can decompile any assembly to IL, edit it and compile it. IL is made to round-trip anything I believe.

usr
  • 168,620
  • 35
  • 240
  • 369
0

Just a suggestion. There could be two PressurePartSize classes: a public one and an internal one. It's not clear from the pictures.

Something like this:

namespace SampleLib
{
    using SampleLib.Internal;
    //using SampleLib.Public;

    public class PublicClass
    {
        public unsafe void PublicMethod(InternalClass internalClass) { }
    }
}

namespace SampleLib.Internal
{
    internal sealed class InternalClass { }
}

namespace SampleLib.Public
{
    public sealed class InternalClass { }
}

Error CS0051 Inconsistent accessibility: parameter type 'InternalClass' is less accessible than method 'PublicClass.PublicMethod(InternalClass)'

But

namespace SampleLib
{
    //using SampleLib.Internal;
    using SampleLib.Public;

    public class PublicClass
    {
        public unsafe void PublicMethod(InternalClass internalClass) { }
    }
}

namespace SampleLib.Internal
{
    internal sealed class InternalClass { }
}

namespace SampleLib.Public
{
    public sealed class InternalClass { }
}

Is OK.

Update

There is only one PressurePartSize, see the updated question.

Than it seems they had Autodesk.Civil.DatabaseServices.Styles.PressurePartSize public at first. Then they created a library with public unsafe ObjectId AddLinePipe(LineSegment3d line, PressurePartSize partSize) and built it. Then they changed Autodesk.Civil.DatabaseServices.Styles.PressurePartSize to internal, but did not rebuilt the calling library. But JIT compiler checks accesability at runtime. That's the reason of the exception you mentioned.

CSDev
  • 3,177
  • 6
  • 19
  • 37