繁体   English   中英

使用Generic Cast to Interface的C#Factory方法

[英]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:

  1. type参数仅用作接口方法的返回类型,不用作方法参数的类型。
  2. type参数不用作接口方法的通用约束。

考虑使用容器的Inversion of Control方法。 各种实现在容器中注册自己。 解析器请查询(x)的实例。 将Unity视为许多IOC容器工具中的一个。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM