Arman Hayots
Arman Hayots

Reputation: 2508

Can I use Activator.CreateInstance with an Interface?

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.

Upvotes: 21

Views: 30127

Answers (7)

dzed
dzed

Reputation: 534

Something that worked for me is creating a dummy object, like this. In case I needed to serialize/create object say in a GraphQL setup.

public interface IMyInterface
{
    string Value { get; }
}


public static class InterfaceCreator
{
    private record MyInterfaceDummy(string Value) : IMyInterface;

    public static IMyInterface? From(string value) => Activator.CreateInstance(typeof(MyInterfaceDummy), [value]) as IMyInterface;
}

Upvotes: 0

fabriciorissetto
fabriciorissetto

Reputation: 10103

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>();

Upvotes: 7

user55993
user55993

Reputation: 311

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);
    }

Upvotes: 2

Myrtle
Myrtle

Reputation: 5851

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.

Upvotes: 4

Botz3000
Botz3000

Reputation: 39670

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();

Upvotes: 26

walther
walther

Reputation: 13598

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.

Upvotes: 3

archil
archil

Reputation: 39501

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();

Upvotes: 5

Related Questions