0

Let's say we have an application called "app.exe" which is using an external assembly called "lib.dll", the assembly contains a static type like following

internal class Foo {
    public static Foo GetInstance(string param1, string param2) {...}
    public static Foo GetInstance(string param2)
    public string Prop { get; set; }
    public string PublicMethod(string param1) { ... }
    protected string ProtectedMethod(string param1) { ... }
}

What is the best way to call Foo.GetInstance(string, string) method and after use this instance? The class is not implementing any interface (nor does it inherit from any public class). An example is really appreciated.

Update: I know about the principle of OOP, but I'm looking for a technically possible solution here. Being it Reflection, Deturing, Hooking etc. but the most preferable is Reflection. This is merely to unblock the dev team before the 3rd party can adopt their code to fix this mistake (unfortunately we are dealing with lots of bureaucracy here).

Update: I made a mistake in the original question, there are multiple GetInstance methods with different signatures.

Reza
  • 115
  • 2
  • 7
  • The internal keyword specifies that Foo cannot be accessed from an external assembly: https://msdn.microsoft.com/en-us/library/7c5ka91b.aspx – poppertech Jul 15 '16 at 09:13
  • http://stackoverflow.com/questions/1259222/how-to-access-internal-class-using-reflection – foobar Jul 15 '16 at 09:19
  • @Eli Arbel, I don't have access to the source code of Foo, otherwise I would even change it to public (for some good reasons). Apparently no one has covered this specific scenario or I could not find it yet. – Reza Jul 15 '16 at 09:26

3 Answers3

4

Use Type.GetType:

var type = Type.GetType("NameSpace.Foo, Assembly");

There the tricky part is the assembly-qualified name, then:

var method = type.GetMethod(
    "GetInstance", 
    BindingFlags.Public | BindingFlags.Static, 
    null, 
    new[] { typeof(string), typeof(string) }, 
    null);
method.Invoke(null, new[] { "param1", "param2" });
Alessandro D'Andria
  • 8,663
  • 2
  • 36
  • 32
  • I didn't know I could use Type.GetType(...) to get the private type directly without getting an instance of Assembly. Anyway the external assembly is indirectly loaded into the domain of executable. I'm gonna give it a try... – Reza Jul 15 '16 at 09:44
  • The first line worked, but I'm getting "Ambiguous match found." exception in type.GetMethod, apparently they have multiple GetInstance methods with different signature, is there a way to make GetMethod return the one I need or do I need to iterate through all methods? – Reza Jul 15 '16 at 09:56
  • @Reza Take a look at the edit, you can pass the parameters. – Alessandro D'Andria Jul 15 '16 at 10:02
  • Now I'm getting an exception complaining about something internal to the application (business logic,...) which basically means that you have nailed it! Thanks a lot for your quick and to the point answer. – Reza Jul 15 '16 at 10:06
2

You can't. This is the meaning of the internal access modifier (Friend in VB). A method marked with internal is accessible only within the assembly that defines it.

Here is the documentation about the internal access modifier.

Bozhidar Stoyneff
  • 3,576
  • 1
  • 18
  • 28
  • Right, but I mean how I can do that by using Reflection? I will update my question to indicate that. – Reza Jul 15 '16 at 09:18
  • AFAIK, with reflection you can discover the types and their members within an assembly, even if the type is marked as private - or in your case `internal`. However in order to invoke the method, even though it is discovered through reflection, you need an actual object to pass to the `MethodInfo.Invoke`. [Check out the documentation.](https://msdn.microsoft.com/en-us/library/system.reflection.methodinfo.invoke(v=vs.110).aspx) – Bozhidar Stoyneff Jul 15 '16 at 09:31
  • I notice the method you want to invoke is `static`. In this case you can invoke it by passing null to the `MethodInfo.Invoke`. Alessandro D`Andria already provided the correct answer. – Bozhidar Stoyneff Jul 15 '16 at 09:39
  • As a note, reflection can bypass any visibility restrictions, so to get an object you can just invoke a non public constructor. In other words, if it exists, reflection can use/invoke it. – thehennyy Jul 15 '16 at 09:41
2

Assuming this class in other lib

namespace PrivateLib
{
    class MyClass
    {
        private static string Foo()
        {
            return "Hello World";
        }
    }
}

you can do

  class Program
    {
        static void Main(string[] args)
        {
            var assembly = Assembly.LoadFile(Path.GetFullPath("PrivateLib.dll"));
            var myClass = assembly.GetType("PrivateLib.MyClass");
            //var instance = myClass.GetConstructor(new Type[]{}).Invoke(new object[] { });
            var method = myClass.GetMethod("Foo", BindingFlags.NonPublic | BindingFlags.Static);
            var result = method.Invoke(null, new object[]{});
            Console.WriteLine(result);
            Console.ReadLine();
        }
    }
Stijn Van Antwerpen
  • 1,840
  • 17
  • 42
  • The class is private and the method is static. Please check the question once more ;) – Reza Jul 15 '16 at 09:37
  • The first parameter in a `MethodInfo.Invoke` call on a static method should be `null`. – thehennyy Jul 15 '16 at 09:44
  • @thehennyy: No, it is not required, the first parameter is ignored with a call on a static method. But is indeed is better. – Stijn Van Antwerpen Jul 15 '16 at 09:46
  • Apart from that, this is absolutely the way to go. The `Assembly` instance can be obtained via other ways if needed, but that should be clear anyway. – thehennyy Jul 15 '16 at 09:51
  • I tried this one as well, as apparently there are multiple Foo methods with different signatures it throws an "Ambiguous match found." exception. Is there any way to get the right one in one go? – Reza Jul 15 '16 at 09:59
  • The approach in the answer is correct too, but Alessandro's was match more precisely the scenario (as the assembly is already referenced and loading an instance of Assembly is not required,...). But thanks for youranswer. It pointed me to the right direction. – Reza Jul 15 '16 at 10:10