开发者

Failing to create type dynamically

开发者 https://www.devze.com 2023-01-31 11:19 出处:网络
I am trying to come up with a method factory that looks inside config to get the full name of the type to instantiate and creates that object type dynamically.

I am trying to come up with a method factory that looks inside config to get the full name of the type to instantiate and creates that object type dynamically.

Here is my Type and the Interface:

public interface IComponent<T> 
{
    IEnumerable<T> DataSource {get; set;}

    void PerformTask(object executionContext);

}

namespace MyCompany.Components 
{
    public class ConcreteComponent1<T> : IComponent<T> 
    {

        private IEnumerable<Contact> contactSource = null;

        internal ConcreteComponent1() {}

        public void PerformTask(object executionContext) 
        {
            this.contactSource = GetSource(executionContext);

            foreach(var result in this.contactSource) 
            {
                result.Execute(executionContext); 
            }
        }

        public IEnumerable<T> DataSource 
        {
            get { return this.contactSource as IEnumerable<T>; }
            set { this.contactSource = (IContactSource)value; }
        }
    }
}

Factory, resides in the same assembly:

//Factory - Same assembly
public s开发者_JAVA技巧tatic class ComponentFactory<T> 
{
    public static IComponent<T> CreateComponent() 
    {
        var assembly = Assembly.GetExecutingAssembly();
        object o = assembly.CreateInstance("MyCompany.Components.ConcreteComponent1"); //o is null...

        var objectHandle = Activator.CreateInstance(Assembly.GetAssembl(typeof(ComponentFactory<T>)).GetName().FullName, "MyCompany.Components.ConcreteComponent1"); //throws Could not load type from assembly exception.                     
        return o as IComponent<T>;
    }
}

So in first case the o is always null.

In the second case when using the Activator class, it throws Type could not be loaded from assembly "MyAssembly". No inner exception. What am I doing wrong?


First of all, actual name of your type is:

MyCompany.Components.ConcreteComponent1`1

It can't be instantiated because you have to specify type parameters:

public static class ComponentFactory<T>
{
    public static IComponent<T> CreateComponent()
    {
        Type generic = Type.GetType("MyCompany.Components.ConcreteComponent1`1");
        Type concrete = generic.MakeGenericType(typeof(T));
        var objectHandle = Activator.CreateInstance(
           concrete,
           BindingFlags.NonPublic | BindingFlags.Instance,
           null,
           null, //here can come ctor params
           null); 
        return objectHandle as IComponent<T>;
    }
}

this will work with internal constructor.


I'd say the actual name of your class ConcreteComponent1 is not "MyCompany.Components.ConcreteComponent1" because it includes a generic. Execute

Console.WriteLine(typeof(ConcreteComponent1<T>).FullName);

to see the string representation for your class created by C#.

But why do you define your ConcreteComponent1 class the way you do? Wouldn't it be better to use something like this:

public class ConcreteComponent1 : IComponent<Contact> {

        internal ConcreteComponent1() {}

        public void PerformTask(object executionContext) 
        {
              this.contactSource = GetSource(executionContext);

              foreach(var result in this.contactSource) 
              {
                    result.Execute(executionContext); 
              }
        }

        public IEnumerable<Contact> DataSource 
        {
              get { return this.contactSource; }
              set { this.contactSource = value; }
        }
   }

This way you can use the expected name you already used in your example and you can remove the extra private field your approach introduces. As your ConcreteComponent1 class doesn't really need any generic functionality this would be a better approach in my opinion.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号