【问题标题】:Failing to create type dynamically无法动态创建类型
【发布时间】:2010-12-21 17:39:44
【问题描述】:

我正在尝试提出一个方法工厂,该方法工厂在 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 类时,它会抛出 Type could not be loaded from assembly "MyAssembly"。没有内在的例外。我做错了什么?

【问题讨论】:

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


    【解决方案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 构造函数。

    【讨论】:

    • 太好了 - 感谢您的提示。但有一件事 - 将构造函数公开将破坏工厂的全部目的。
    • @Max Malygin 检查编辑,您需要添加更多参数来启用internal ctor
    • 好的,我想一定有办法。
    【解决方案2】:

    我会说你的类 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 类实际上并不需要任何通用功能,因此我认为这将是一种更好的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-21
      • 2017-02-23
      • 1970-01-01
      • 2014-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多