无法动态创建类型

时间:2010-12-21 17:39:44

标签: c# .net .net-3.5 dynamic factory

我正在尝试创建一个方法工厂,该工厂查看config内部以获取要实例化的类型的全名,并动态创建该对象类型。

这是我的类型和界面:

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 - Same assembly
public static 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>;
    }
}

因此,在第一种情况下, o 始终为空。

在使用Activator类的第二种情况下,它抛出无法从程序集“MyAssembly”加载Type。没有内在的例外。我做错了什么?

2 个答案:

答案 0 :(得分:1)

我会说你的类ConcreteComponent1的实际名称不是“MyCompany.Components.ConcreteComponent1”,因为它包含一个泛型。执行

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

查看由C#创建的类的字符串表示形式。

但是你为什么要这样定义你的ConcreteComponent1类呢?使用这样的东西不是更好:

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

通过这种方式,您可以使用您在示例中使用的预期名称,并且可以删除方法引入的额外私有字段。由于您的ConcreteComponent1类并不真正需要任何通用功能,因此我认为这是一种更好的方法。

答案 1 :(得分:1)

首先,您的类型的实际名称是:

MyCompany.Components.ConcreteComponent1`1

无法实例化,因为您必须指定类型参数:

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

这将适用于internal构造函数。