Неспособность создать тип динамически - PullRequest
0 голосов
/ 21 декабря 2010

Я пытаюсь найти фабрику методов, которая просматривает конфигурацию, чтобы получить полное имя типа для создания экземпляра и динамически создает этот тип объекта.

Вот мой тип и интерфейс:

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". Нет внутреннего исключения. Что я делаю не так?

Ответы [ 2 ]

1 голос
/ 21 декабря 2010

Прежде всего, фактическое имя вашего типа:

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 конструктор.

1 голос
/ 21 декабря 2010

Я бы сказал, что фактическое имя вашего класса 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 на самом деле не нуждается в какой-либо общей функциональности, на мой взгляд, это был бы лучший подход.

...