简体   繁体   中英

Activator.CreateInstance with dynamic Type

I think I have a lack of understand, what exactly is happening: The user can enter a Path to an Assembly and an Object type and I try to create a instance of it.

My approach:

        Assembly a = Assembly.LoadFile(txtAssemblyPath.Text);
        Type myType = a.GetTypes().ToList().FirstOrDefault(f => f.Name == txtObjectName.Text);

        var obj = Activator.CreateInstance<myType>();
        var obj2 =(myType) Activator.CreateInstance(myType);

The problem is in the Creation of the Object itself. It seems like the myType is not threated as a Type. On this example: Creating generic variables from a type - How? Or use Activator.CreateInstance() with properties { } instead of parameters ( )?

They just get an object, so I guess this is not the same Case. What I dont understand at all: CreateInstance(Type) works, but CreateInstance with the Type doesn't, but T and Type should be the same: System.Type.

Thanks in advance for clarifying.

Matthias

There are a using difference... When you write:

var obj = Activator.CreateInstance<myType>();

You used your Class like a Type, and it's the good way to do it. You used a generic type who have a reference to a class type.

But there:

var obj2 =(myType) Activator.CreateInstance(myType);

You used you class like an instance (object). And you can't do that, a class is a schema. If you want to call the second method, you have to write:

var obj2 =(myType) Activator.CreateInstance(typeof(myType));

This code will create an instance of the class Type, and this instance will describe your class myType.

I hope to be clear.

A class is a schema, you can create an object with this schema, it will be an instance (a memory-object of your class).

When you use generic type of method such as Activator.CreateInstance<T>(); you have to provide Strong Type of T. That means you have to pass known type name instead of T. for example:

var activatorPerson = (Person)Activator.CreateInstance<Person>();

That's why there is a non generic form of Activator.CreateInstance(typeGoesHere) function which can be used in cases that we do not have a Strong Type at moment of creation of an object. So we can pass type as a parameter to that function. we can provide type variable in lots of ways. In your case you find the proper type in your assembly as following:

Type myType = a.GetTypes().ToList().FirstOrDefault(f => f.Name == txtObjectName.Text);

also you have to notice that explicit casting as you typed in your code is not valid:

obj2 =(myType) Activator.CreateInstance(myType);

because you have to provide Strong Type name for explicit casting. when we do not have access to strong type names at run time, we have to use non generic versions of methods.

Here is the pure dynamic way.

This is the factory class and dynamic instance create method:

    public class RepositoryFactory
{
    public static dynamic CreateDynamic<TEntity>() where TEntity : BaseEntity
    {
        dynamic repositoryInstance = null;
        var subRepositories = AssemblyHelper.GetSubclassesOf(typeof(BaseRepository<TEntity>), true);
        var entityTypeName = typeof(TEntity).Name;
        var subRepository = subRepositories.FirstOrDefault(x => x.Name == entityTypeName + "Repository");
        if (subRepository != null)
        {
            var repositoryType = subRepository.UnderlyingSystemType;
            repositoryInstance = Activator.CreateInstance(repositoryType);
        }
        return repositoryInstance;
    }
}

This is the helper class for mapping types between Entity and Repository.

public static class AssemblyHelper
{
        public static List<Type> GetSubclassesOf(Type type, bool ignoreSystem)
        {
            List<Type> lReturn = new List<Type>();
            foreach (var a in System.Threading.Thread.GetDomain().GetAssemblies())
            {
                if (ignoreSystem && a.FullName.StartsWith("System."))
                {
                    continue;
                }
                foreach (var t in a.GetTypes())
                {
                    if (t.IsSubclassOf(type) || (type.IsInterface && t.GetInterfaces().FirstOrDefault(e => e.FullName == type.FullName) != null))
                    {
                        lReturn.Add(t);
                    }
                }
            }
            return lReturn;
        }
}

This is the Manager class for use case:

public class PageManager
{
    private readonly ContentPageRepository _pageRepository;
    public PageManager()
    {
        _pageRepository = RepositoryFactory.CreateDynamic<ContentPage>();
    }

    public void GetPagesByContentType(ContentType type)
    {
        var pages = _pageRepository.GetByPredicate(x => x.Status != EntityStatus.Deleted && x.Node.Type == type);
        foreach (var page in pages)
        {
            //Deal with it :)
        }

    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM