2012-03-07 86 views
3

我有一个应用程序被构造为一个服务层,它使用存储库层进行持久化。 我想创建一个泛型控制器类来重用共享行为,但我在尝试设置泛型参数时遇到了问题。以下代码:隐式转换en C#泛型类

public class BusinessEntity 
{ } 

public class Person : BusinessEntity 
{ } 

public interface IRepository<T> where T : BusinessEntity 
{ } 

public interface IService<T, R> 
    where T : BusinessEntity 
    where R : IRepository<T> 
{ } 

public partial interface IPersonRepository : IRepository<Person> 
{ } 

public interface IPersonService : IService<Person, IPersonRepository> 
{ } 

public abstract class BaseController<X, Y> 
    where X : BusinessEntity 
    where Y : IService<X, IRepository<X>> 
{ } 

public class PersonController : BaseController<Person, IPersonService> 
{ } 

在编译失败并

类型ConsoleApplication.IPersonService不能在通用类型或方法ConsoleApplication.BaseController<X,Y>被用作类型参数Y。有一个从ConsoleApplication.IPersonServiceConsoleApplication.IService<ConsoleApplication.Person,ConsoleApplication.IRepository<ConsoleApplication.Person>>

这个作品

public interface IPersonService : IService<Person, IRepository<Person>> 

没有隐式引用转换,但我失去了自定义库

有一种方法,使编译器实现IPersonRepositoryIRepository<Person>

+1

权,这是因为'IRepository 其中X:Person'是不一样的'IRepository '默认情况下,默认情况下这种通用类型没有差异。你正在使用哪个版本的.NET Framework? – sll 2012-03-07 19:51:54

+0

如果我有能力,我会给你一个“打破编译器”徽章。从我花了5分钟的时间努力使其工作,我的直觉结论是,编译器不够聪明,无法做你想做的事情。 – PlayDeezGames 2012-03-07 20:03:21

+0

我正在使用.Net 4.我没有想过差异,我认为它值得一试。 – 2012-03-08 21:55:23

回答

4
public class BusinessEntity 
{ } 

public class Person : BusinessEntity 
{ } 

public interface IRepository<T> where T : BusinessEntity 
{ } 

public interface IService<T, R> 
    where T : BusinessEntity 
    where R : IRepository<T> 
{ } 

public partial interface IPersonRepository : IRepository<Person> 
{ } 

public interface IPersonService : IService<Person, IPersonRepository> 
{ } 

public abstract class BaseController<X, Y, Z> 
    where X : BusinessEntity 
    where Y : IService<X, Z> 
    where Z : IRepository<X> 
{ } 

public class PersonController : BaseController<Person, IPersonService, IPersonRepository> 
{ } 

为了解决您的评论:

IPersonService可扩展基础服务类添加自定义的设施,如FindPersonsUnderAge()。为此,它需要一个自定义存储库。实际上,LINQ避免了很多自定义存储库代码,但有时它们是必需的。

如果不要求存储库类型是类型参数,IPersonService不能做到这一点吗?例如:

public interface IService<T> where T : BusinessEntity { } 

public interface IPersonService : IService<Person> 
{ 
    IEnumerable<Person> FindPersonsByAge(double minAge, double maxAge); 
} 

public class Service<T, R> : IService<T> 
    where T : BusinessEntity 
    where R : IRepository<T> 
{ } 

public class PersonService : Service<Person, IPersonRepository>, IPersonService 
{ } 
+0

我不完全喜欢UI开发人员必须知道存储库的事实,但这是一个可以接受的折中方案。 – 2012-03-08 21:59:49

+0

@JamesGordon在这种情况下,我会为'interface IPersonService:IService '拍摄,因此服务的使用者不需要知道服务如何保存其数据 - 甚至不需要依赖于IRepository < >'。 PersonService的哪些方法需要人员存储库的类型参数? – phoog 2012-03-12 19:54:13

+0

IPersonService可以扩展基本服务类以添加自定义设施,如FindPersonsUnderAge()。为此,它需要一个自定义存储库。实际上,LINQ避免了很多自定义存储库代码,但有时它们是必需的。 – 2012-03-13 12:06:03

0

感谢SLL指着我在正确的方向

public interface IService<T, out R> 
    where T : BusinessEntity 
    where R : IRepository<T> 
{ } 

的伎俩