我有以下课程:
// -- model hierarchy
public interface IJob {
}
public abstract class AbstractJob : IJob {
}
public class FullTimeJob : AbstractJob {
}
// -- dao hierarchy
public interface IJobDao<T> where T : IJob {
T findById(long jobId);
long insert(T job);
}
public interface IFullTimeJobDao : IJobDao<FullTimeJob> {
}
public abstract class AbstractDao {
}
public abstract class AbstractJobDaoImpl<T> : AbstractDao, IJobDao<T> where T : IJob {
public T findById(long jobId) {
// omitted for brevity
}
public long insert(T job) {
// omitted for brevity
}
}
public class FullTimeJobDaoImpl : AbstractJobDaoImpl<FullTimeJob>, IFullTimeJobDao {
}
我从工厂方法调用以下代码,这似乎不起作用:
public IJobDao<IJob> createJobDao(long jobDaoTypeId)
{
object jobDao = Activator.CreateInstance(typeof(FullTimeJobDaoImpl));
return jobDao as IJobDao<IJob>; // <-- this returns null
return (IJobDao<IJob>) jobDao; // <-- this cast fails
}
这种“向上演员”是如何正确实现的?
答案 0 :(得分:4)
使IJobDao
接口协变:
public interface IJobDao<out T> where T : IJob
{
T findById(long jobId);
}
<强>更新强>
您不能让接口方法同时返回和接受通用值,并使其同时协变。
可能的解决方案:
IJobDao<T>
的非通用版本 - IJobDao
(当然,您必须在类中实现这两个接口,实现IJobDao<T>
)IJobDao<T>
拆分为2个接口(一个协变和一个逆变)IJobDao
的解决方案(无论如何你都没有获得任何类型安全性,这是泛型的主要目的)关于实施第一个方案的一些想法:
public interface IJobDao
{
IJob findById(long jobId);
long insert(IJob job);
}
public interface IJobDao<T> : IJobDao
where T : IJob
{
new T findById(long jobId);
new long insert(T job);
}
public abstract class JobDaoBase<T> : IJobDao<T>, IJobDao
where T : IJob
{
public abstract T findById(long jobId);
public abstract long insert(T job);
IJob IJobDao.findById(long jobId)
{
return findById(jobId);
}
long IJobDao.insert(IJob job)
{
return insert((T)job);
}
}
public class FullTimeJobDaoImpl : JobDaoBase<FullTimeJob>
{
public override FullTimeJob findById(long jobId)
{
// implementation
}
public override long insert(FullTimeJob job)
{
// implementation
}
}
// we are still unable to return generic interface, but we don't need to.
public static IJobDao createJobDao(/* my params */)
{
object jobDao = Activator.CreateInstance(typeof(FullTimeJobDaoImpl));
return jobDao as IJobDao;
}
答案 1 :(得分:3)
为了使这个演员成为可能,您需要将接口类型参数标记为out
:
public interface IJobDao<out T> where T : IJob {...}
然后
object jobDao = Activator.CreateInstance(typeof(FullTimeJobDaoImpl));
var r = jobDao as IJobDao<IJob>; //not null
但是这会给界面带来一些限制。请阅读out (Generic Modifier) (C# Reference)了解详情。
在通用接口中,如果是,则可以将类型参数声明为协变 它满足以下条件:
- type参数仅用作接口方法的返回类型,不用作方法参数的类型。
- 类型参数不用作接口方法的通用约束。
醇>
答案 2 :(得分:0)
考虑对容器使用Inversion of Control方法。各种实现在容器中注册自己。解析器请查询(x)的实例。 将Unity视为许多IOC容器工具中的一个。