0

i have two classes: Class1 and Class2

class Class1
{
    public void method();
}

class Class2
{
    public void method();
}

in another place I have the class type and I want to create an instance from it. type is typeof(Class1) or typeof(Class2)

public void CreateInstance(Type type)
{
    var instance = Activator.GetInstance(type);
    instance.method(); //compile error: object doesn't contain method
}

a solution is I define an interface that my classes implement that interface.

interface IInterface
{
    void method();
}

public void CreateInstance(Type type)
{
    var instance = Activator.GetInstance(type);
    ((IInterface)instance).method();
}

because I can't access to class definition I can't do this. How can I do this?

mohammad
  • 1,248
  • 3
  • 15
  • 27
  • 2
    You can use `dynamic` instead of `var` as a quick&dirty solution. What do you mean that you can't access the definitions though? You mean that you can't modify them? – Panagiotis Kanavos May 15 '15 at 08:12
  • 1
    He probably means that he doesn't implement the classes himself. Probably they come from some sort of library. – Thorsten Dittmar May 15 '15 at 08:13

3 Answers3

4

This is what you need:

public void CreateInstance(Type type)
{
    var instance = Activator.CreateInstance(type);
    type.GetMethod("method").Invoke(instance, null);
}

Or, alternatively, use dynamic:

public void CreateInstance(Type type)
{
    dynamic instance = Activator.CreateInstance(type);
    instance.method();
}

NB: You had GetInstance instead of CreateInstance in your code, but I corrected it.

Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • You were a minute faster ;) – Markus May 15 '15 at 08:13
  • 3
    Or use `dynamic`. Any type safety is already lost and dynamic is easier (and faster) than reflection – Panagiotis Kanavos May 15 '15 at 08:13
  • I think the first solution is better. because I can check method really exist. – mohammad May 15 '15 at 08:20
  • @mohammad not really - what are you going to do if it doesn't? Throwing an exception is the same as detecting the missing method and trying to work around it in this case. – Panagiotis Kanavos May 15 '15 at 08:23
  • @PanagiotisKanavos Worst case, you can throw a more appropriate exception. – Rawling May 15 '15 at 08:37
  • @Rawling it doesn't get more appropriate than the purpose-built [RuntimeBinderException](https://msdn.microsoft.com/en-us/library/microsoft.csharp.runtimebinder.runtimebinderexception%28v=vs.110%29.aspx). Catching and rethrowing this to an application specific exception isn't hard either. Nothing changes really, except that reflection always pays a performance penalty, even if there are no issues. Worse, you *can* forget to check for the method, resulting in a much worse `NullReferenceException` or even erroneous execution. – Panagiotis Kanavos May 15 '15 at 08:47
  • @PanagiotisKanavos - No, don't rethrow or even allow the exception. This isn't an exceptional case. It's something that can, and should, be programmed to avoid. Eric Lippert calls these kinds of exceptions **boneheaded** and says that if you can avoid them but don't then they are bugs in your code. Read this: http://ericlippert.com/2008/09/10/vexing-exceptions/ – Enigmativity May 15 '15 at 09:47
  • @Enigmativity you may say that the OP's code is buggy then, as the only way to avoid such problems is to use strong typing. Trying to call a non-existent method though *is* an exceptional case and probably *is* a bug - the wrong type was passed, or the method call is wrong. Whether you use reflection and a null check, or catch the exception that says the method is missing - *why was the wrong type passed and what should be done about it* ? – Panagiotis Kanavos May 15 '15 at 09:52
  • @PanagiotisKanavos - It's not exceptional at all. You can check if the method exists with a simple `if` statement. We have no idea what the logic is or what the method does. All we can do is suggest what the right way to handle the situation if the method is missing. – Enigmativity May 15 '15 at 09:59
  • @Enigmativity what is the right way? Gobble it or return 0, false or -1? How can processing continue if a call failed because of a missing method? What happens when this error propagates and eg. you end up with a `-1` exchange rate and `-100%` performance on a customer's portfolio statement? (true story) – Panagiotis Kanavos May 15 '15 at 10:01
  • BTW your code will throw NullReferenceException without any info if the method is missing - it *is* treating this as exceptional but it isn't providing any info. Using `dynamic` will throw `RuntimeBinderException` specifying the missing method. – Panagiotis Kanavos May 15 '15 at 10:03
  • @PanagiotisKanavos - You're being argumentative. I did say that we have no idea what the required logic is. If we did we could suggest what to do. But that doesn't change the fact that we should strive to write code that doesn't throw exceptions. That's what the OP should be doing. It would be wrong for us to suggest he throw an exception. We just don't know what his logic requirement is. – Enigmativity May 15 '15 at 10:32
1

You can avoid reflection and performance issues entirely by using a generic method and dynamic:

public void CreateInstance<T>() where T:new()
{
    dynamic instance=new T();
    instance.method();
}

Which you can call simply by passing the type:

CreateInstance<Class1>();
CreateInstance<Class2>();

Type safety is lost either when using reflection or using dynamic. Checking for the existence of a method with reflection isn't any safer or less risky than having the runtime throw an exception - in both cases you have to handle an exceptional condition. What are you going to do when this exception occurs?

With dynamic, a missing method will raise a RuntimeBinderException specifying that a method is missing. If I changed the method call from method to method1 I'll get an exception saying:

'ConsoleApplication24.Class1' does not contain a definition for 'method1'

This way the code does not pay the reflection penalty for the normal cases. This is also safer - there is no way that the exception can be missed.

The only way that provides compile-type safety is to have the classes implement an interface and use it as a generic constraint, eg:

public static void CreateInstance<T>() where T : ISomething, new()
{
    var instance = new T();
    instance.method();
}
Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
0

Best option would be to use interface for safety. But if you can't do that, you can invoke this method through reflection:

public class MyClass
{
    public void Method()
    {
        Console.WriteLine("executed");
    }
}

public class MyActivator
{
    public static void CreateInstance(Type type)
    {
        var instance = Activator.CreateInstance(type);

        var method = GetMethod("method");
        method.Invoke(instance, null);
    }
}

And then you call this by:

MyActivator.CreateInstance(typeof(MyClass));

Remember to add some checking if method is not null

Michal Dymel
  • 4,312
  • 3
  • 23
  • 32