[英]c# cannot cast object to interface in a method with multiple generic parameters
[英]C# Factory Method with Generic Cast to Interface
我有以下课程:
// -- 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
}
这种“向上演员”是如何正确实现的?
使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;
}
要使此转换成为可能,您需要将接口类型参数标记为out
:
public interface IJobDao<out T> where T : IJob {...}
然后
object jobDao = Activator.CreateInstance(typeof(FullTimeJobDaoImpl));
var r = jobDao as IJobDao<IJob>; //not null
但这会给界面带来一些限制。 读出(通用修饰符)(C#参考)了解更多信息。
在通用接口中,如果类型参数满足以下条件,则可以将其声明为covariant:
- type参数仅用作接口方法的返回类型,不用作方法参数的类型。
- type参数不用作接口方法的通用约束。
考虑使用容器的Inversion of Control方法。 各种实现在容器中注册自己。 解析器请查询(x)的实例。 将Unity视为许多IOC容器工具中的一个。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.