Can I use Activator.CreateInstance with an Interface?
Asked Answered
J

6

20

I have an example:

        Assembly asm = Assembly.Load("ClassLibrary1");
        Type ob = asm.GetType("ClassLibrary1.UserControl1");
        UserControl uc = (UserControl)Activator.CreateInstance(ob);
        grd.Children.Add(uc);

There I'm creating an instance of a class, but how can I create an instance of a class which implements some interface? i.e. UserControl1 implements ILoad interface.

U: I can cast object to interface later, but I don't know which type in the assemblies implements the interface.

Jolinejoliotcurie answered 24/5, 2012 at 7:22 Comment(2)
You can't create an instance of an interface; you can create the class implementing the interface and pass it as the interface.Intercalation
You can't instantiate an object of the type ILoad, it's an interface.Nanice
M
25

This is some code i have used a few times. It finds all types in an assembly that implement a certain interface:

Type[] iLoadTypes = (from t in Assembly.Load("ClassLibrary1").GetExportedTypes()
                     where !t.IsInterface && !t.IsAbstract
                     where typeof(ILoad).IsAssignableFrom(t)
                     select t).ToArray();

Then you have all types in ClassLibrary1 that implement ILoad.

You could then instantiate all of them:

ILoad[] instantiatedTypes = 
    iLoadTypes.Select(t => (ILoad)Activator.CreateInstance(t)).ToArray();
Marsden answered 24/5, 2012 at 7:32 Comment(5)
I'm getting the following error: Could not find an implementation of the query pattern for source type 'System.Reflection.Assembly'. 'Where' not found.Hart
Found it. Load("ClassLibrary1") in the above code should be followed by .GetExportedTypes();.Hart
@Hart Yeah that call should be there. I've added it now.Marsden
@bookmarker You need to know the type parameter in order to cast. If you don't know that, you could use a non-generic base interface. Generic classes or interfaces are not so easy to use anymore if you don't know the type parameter.Marsden
Hi. Any idea on how to do this in a portable class? 't' does not seem to have IsInterface or IsAbstract nor does Type have IsAssignableFrom. I am trying to activate an instance from an interface inside a portable class library project so I can use it inside Xamarin.Ernaldus
S
6

The only problem with the accepted answer is that you must have a concrete class on your assembly that implements the interface.

To avoid that I have created my CustomActivator that is able to create a dynamic object at runtime and make it implements the desired interface.

I put it on the github: https://github.com/fabriciorissetto/CustomActivator

The call is simple:

CustomActivator.CreateInstance<MyInterface>();
Squatter answered 17/5, 2015 at 3:6 Comment(0)
D
5

You cannot create instance of an interface, but if

UserControl1 implements ILoad inteface

you can use resulting object as ILoad

ILoad uc = (ILoad)Activator.CreateInstance(ob);
grd.Children.Add(uc);

Moreover, you do not need to treat it via interface, if you write

UserControl1 uc = (UserControl1)Activator.CreateInstance(ob);
grd.Children.Add(uc);

Members of ILoad would be callable as uc.SomeILoadMethod();

Dhiren answered 24/5, 2012 at 7:25 Comment(3)
Provided ob is still a type representing a class and not an interface.Adkinson
@Adkinson constructed object implements ILoad, so it can be used directlyDhiren
OK, but how I can find type in assembly, which implements ILoad?Jolinejoliotcurie
B
4

What you want can be achieved using a IoC container like `NInject'. You can configure a container to return a concrete type when you've requested an interface.

Begonia answered 24/5, 2012 at 7:28 Comment(0)
P
3

Interface is an interface. It's a template. Why would you want to instantiate an interface? Implement the interface and instantiate that class. You can't instantiate an interface, it doesn't really make sense.

Paleontography answered 24/5, 2012 at 7:26 Comment(1)
Of course it makes sense to have an easy way of instantiate an interface. Imagine DTOs. POCOs with no behavior. You want to create them as interfaces in order to use them easily in a mock framework, but when you implement the interface, you basically end up with two identical pieces of code that you need to maintain. That is why some frameworks, like NServiceBus, lets you "instantiate interfaces". I am not saying that it can be done easily with built in features like the Activator, I am just saying that you cannot blow this off as "doesn't make sense"Ossify
L
2

If the library was referenced in the project you may use:

    static public IEnumerable<Type> GetTypesFromLibrary<T>(String library)
    {
        var MyAsemblies = AppDomain.CurrentDomain.GetAssemblies()
                         .Where(a=>a.GetName().Name.Equals(library))
                         .Select(a=>a);
        var Exported = MyAsemblies
                         .FirstOrDefault()
                         .GetExportedTypes();
        var Asignable = Exported
                         .Where (t=> !t.IsInterface && !t.IsAbstract
                         && typeof(T).IsAssignableFrom(t))
                         .Select(t=>t)
                         .AsEnumerable();
        return Asignable;
    }

    static public T GetInstanceOf<T>(String library, String FullClassName)
    {
        Type Type = GetTypesFromLibrary<T>(library)
                        .Where(t => t.FullName.Equals(FullClassName))
                        .FirstOrDefault();
        if (Type != null)
        {
            T Instance = (T)Activator.CreateInstance(Type);
            return Instance;
        }
        return default(T);
    }
Laxative answered 12/7, 2014 at 4:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.