这让我感到困惑,所以这个问题可能会令人困惑。
我有一个应用程序,它使用IJob接口的实现来完成不同的任务。
public interface IJob
{
int Id { get; set; }
string Name { get; set; }
void Run();
}
我使用Castle.Windsor.WindsorContainer来解决这些实现,并使用服务ID来帮助识别它们。
WindsorContainer container = new WindsorContainer(new XmlInterpreter());
IJob jobToExecute = container.Resolve<IJob>("nameOfJob");
我写了一个小的通用扩展方法,它只是将SQL列的值放入相应的属性中。
public static void MapTo<T>(this DbDataReader reader, ref T instance) where T : class
{
Type objectType = typeof(T);
foreach (PropertyInfo propertyInfo in objectType.GetProperties())
{
if (propertyInfo.CanWrite)
{
int ordinal = -1;
try
{
ordinal = reader.GetOrdinal(propertyInfo.Name);
object value = reader[ordinal] == DBNull.Value ? null : reader[ordinal];
propertyInfo.SetValue(instance, value, null);
}
catch (IndexOutOfRangeException ex)
{
continue;
}
}
}
}
现在,因为您无法实例化接口的实例,所以将IJob传递给此方法将不起作用。但是,为了获得IoC容器的好处,我需要使用IJob接口在我的存储库中完成所有操作。所以,我写这篇文章来解决IJob实现,并将它传递给MapTo方法来填充必要的属性:
public IJob GetJobById(int id)
{
string cmdTxt = "SELECT Id, Name, Description, DateStarted, ScheduledCompletion, Completed FROM Jobs WHERE Id = @id";
using (DbCommand cmd = _dataFactory.CreateCommand(cmdTxt))
{
_dataFactory.AddParam(cmd, "id", id, DbType.Int32);
using (DbDataReader rdr = cmd.ExecuteReader())
{
if (rdr.Read())
{
IJob job = _container.Resolve<IJob>("job.implementation");
rdr.MapTo<IJob>(ref job);
return job;
}
else
{
return null;
}
}
}
}
这是一个好的设计决定吗?你看到有什么问题吗?
答案 0 :(得分:1)
嗯,首先,通过反射调用方法通常不太好...而且看起来你正在使用Windsor作为类型字典,它不是......
我会编写一个非通用的MapTo
(可以使用Type
作为参数),它对已经存在的实例进行操作(当您使用Activator.CreateInstance
创建新实例时丢弃Windsor已解决的实例),然后在ComponentCreatedEvent
中的IKernel
事件中使用它。像这样:
container.Kernel.ComponentCreated += (model, instance) => {
if (model.Service == typeof(IJob)) {
// select id,name from jobs where id = model.Name
// use MapTo to fill id,name into instance
}
}