Bes Ley
Bes Ley

Reputation: 1797

How to invoke method only from interface and method name?

In my program, we referenced another assembly, and there is an implement instance in that assembly definitely. So we want to invoke its method at run-time. We have known the interface and method name, but the implement instance name is not certainly. How I can invoke method only from interface and method name?

Type outerInterface = Assembly.LoadAssembly("AnotherAssemblyFile").GetTypes()
     .Single(f => f.Name == "ISample" && f.IsInterface == true);
Object instance = Activator.CreateInstance(outerInterface);
MethodInfo mi = outerInterface.GetMethod("SampleMethod");
var result = mi.Invoke(instance, new object[]{"you will see me"});

The exception is thrown:

An unhandled exception of type 'System.MissingMethodException' occurred in mscorlib.dll

Additional information: Cannot create an instance of an interface.

The referenced assembly code is here:

namespace AnotherAssembly
{
    public interface ISample
    {
        string SampleMethod(string name);
    }

    public class Sample : ISample
    {
        public string SampleMethod(string name)
        {
            return string.Format("{0}--{1}", name, "Alexsanda");
        }
    }
}

But the reflection part not work, I am not sure how I can make it work well.

Edit: I don't know the instance name clearly, only know the interface name and method name. But I know there is an implement class from the interface in that assembly definitely.

Upvotes: 1

Views: 1516

Answers (3)

Alex Booker
Alex Booker

Reputation: 10777

Your error message is really clear: you cannot create an instance of an interface. Imagine if you wrote...

var x = new ISample()

... In normal code. It makes no sense at all.

The error stems from these lines of code...

Type outerInterface = Assembly.LoadAssembly("AnotherAssemblyFile").GetTypes()
     .Single(f => f.Name == "ISample" && f.IsInterface == true);
Object instance = Activator.CreateInstance(outerInterface);

... In the above listing you find the interface itself and then attempt to instantiate it.

What you really want to do is find a type that implements the interface and instantiate that instead...

Type type = Assembly.Load("AnotherAssembly")
    .GetTypes()
    .Single(t => t.GetInterfaces().Contains(typeof(ISample)));
ISample instance = (ISample) Activator.CreateInstance(type);
string result = instance.SampleMethod("test");

... Note how I cast the instance to ISample -- this removes the need to call GetMethod.

If you do not already have a reference to the assembly, you can do this:

Type[] types = Assembly
    .Load("AnotherAssembly")
    .GetTypes();
Type sampleInterface = types
    .Single(f => f.Name == "ISample" && f.IsInterface == true);
Type type = types
    .Single(t => t.GetInterfaces().Contains(sampleInterface));
object instance = Activator.CreateInstance(type);
MethodInfo method = type.GetMethod("SampleMethod");
string result = (string) method.Invoke(instance, new object[] { "you will see me" });

Upvotes: 3

vc 74
vc 74

Reputation: 38179

You cannot instantiate an interface but you can find the class implementing it:

Assembly assembly = Assembly.LoadAssembly("AnotherAssemblyFile");
Type[] assemblyTypes = assembly.GetTypes();

Type ISampleType = assemblyTypes.GetType("NameSpace.ISample");

Type sampleType = assemblyTypes.Single(type => 
                  (type != ISampleType) && ISampleType.IsAssignableFrom(type));

object instance = Activator.CreateInstance(sampleType);
MethodInfo mi = sampleType .GetMethod("SampleMethod");
var result = mi.Invoke(instance, new object[]{"you will see me"});

Upvotes: 1

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236208

You cannot create instance of interface type, because interface is just an API, it's a contract definition and nothing else. Actually if you'll try to instantiate interface, you'll get exception:

System.MissingMethodException: Cannot create an instance of an interface.

So you need to get type which implements your interface and instantiate instance of that type:

var anotherAssemblyTypes = Assembly.LoadAssembly("AnotherAssemblyFile").GetTypes();
// get interface type
Type outerInterface = anotherAssemblyTypes
                        .Single(t => t.Name == "ISample" && t.IsInterface);
// find class which implements it
Type outerClass = anotherAssemblyTypes
                        .Single(t => !t.IsInterface && outerInterface.IsAssignableFrom(t));
// instantiate class
dynamic obj = Activator.CreateInstance(outerClass);
string result = obj.SampleMethod("Bob");

Of course you don't have to use dynamic object here. I used it just to test SampleMethod is called.

Upvotes: 1

Related Questions