我正在尝试创建一个方法工厂,该工厂查看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。没有内在的例外。我做错了什么?
答案 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
构造函数。