这是我需要帮助的代码的一部分:
// simple service locator
public class ServiceManager<TSvc> : IServiceManager<TSvc> where TSvc: class, IService
{
private Dictionary<object, TSvc> services;
public void RegisterService(TSvc service)
{
// omitted code here
this.services.Add(service.GetType(), service); // dictionary
}
public T GetService<T>() where T : TSvc
{
T result = default(T);
TSvc bufResult = null;
if (this.services.TryGetValue(typeof(T), out bufResult))
result = (T)bufResult;
return result;
}
public TSvc GetService(Type serviceType)
{
TSvc result = null;
this.services.TryGetValue(serviceType, out result);
return result;
}
}
然后我的域名接口:
public interface IItem
{
string Name { get; set; }
}
public interface IRepository<TModel> where TModel : IItem
{
new IEnumerable<TModel> GetItems();
void InsertItem(TModel item);
void UpdateItem(TModel item);
void DeleteItem(TModel item);
}
public interface IService<TModel> where TModel : IItem
{
IRepository<TModel> Repository { get; }
}
然后我的一些域类:
public class Book: IItem
{
public string Name { get; set; }
}
public class BookRepo: IRepository<Book>
{
new IEnumerable<Book> GetItems();
void InsertItem(Book item);
void UpdateItem(Book item);
void DeleteItem(Book item);
}
public class BookService: IService<Book>
{
IRepository<Book> IService<Book>.Repository { get { return this.Repository; } }
BookRepo Repository { get; set;}
}
现在,如果我有兴趣使用'BookService'并对它做一些事情,我可以从服务定位器那样得到它:
public void DoSomething()
{
var bookService = serviceManager.GetService<BookService>();
bookService.Repository.Insert(new Book());
}
但问题是服务的类型仅在运行时才知道(例如,从组合框中选择)。那么,DoSomething方法怎么样?
public void DoSomething()
{
var typeOfService = combobox.SelectedValue.GetType(); // cbx of services
// ??? make use of serviceManager and typeOfService to get appropriate 'service'
service.Repository.Insert(/*new IITem here*/);
}
此外,我想知道您如何将IService
连接到IService<TModel>
...它甚至可以找到解决方案,但我不知道如何。我的IService
界面目前是空白的......
我非常感谢你的时间。如果有什么不清楚的地方请告诉我!谢谢!
更新:根据您的回答,我猜可能会涉及反射部分(类似于NSGaga指出的那样),但仍然没有连接IService
和IService<TModel>
我无法实现我想要的。谁知道如何重新设计呢?
答案 0 :(得分:2)
这样的东西应该有用(从头开始输入,所以你需要检查语法细节 - 但是应该给你方向 - 或者我稍后会添加)
MethodInfo methodInfo = typeof(ServiceManager).GetMethod("GetService");
MethodInfo methodInfoGeneric = methodInfo.MakeGenericMethod(new[] { typeOfService });
methodInfoGeneric.Invoke(serviceManager, new object[] { });
答案 1 :(得分:2)
要调用只在运行时知道类型的泛型方法,需要使用反射。
例如,在上一个代码示例中,您正确地暗示您无法致电GetService<BookService>
,但您仍在向服务添加new Book()
。您还必须使用反射来实例化新对象,因为再次,您在编译时不知道类型。因此,您需要至少使用三次反射:一次调用返回服务的方法,一次调用创建新对象,一次调用服务上的insert方法。
您可以使用dependency injection和inversion of control来区分这种复杂性。例如,创建如下通用方法:
void CreateNewObject<T>() where T : new()
{
var service = GetServiceFor<T>();
service.Repository.Insert(new T());
}
现在,您只需要使用一次反射来调用该方法,而不是三次。