有人可以解释为什么这不是有效的实施吗?

时间:2015-07-29 17:13:33

标签: c# interface polymorphism

public class ServiceCodeController : ControllerBase {
    // the red squiggly under IJobRepository is saying it's not convertible
    private LazyRepo<IJobRepository> _domainRepo2; 
}

public class LazyRepo<TRepo> where TRepo : IRepository<IDomainEntity> { ... }

public interface IJobRepository : IRepository<JobDomain>, IListRepository { ... }

public interface IRepository<T> : IRepositoryRead<T>, 
    IRepositoryCreate<T>, 
    IRepositoryDelete<T>, 
    IRepositoryUpdate<T> 
    where T : IDomainEntity { ... }

public class JobDomain : BaseDomainEntity { ... }

public abstract class BaseDomainEntity : IDomainEntity, 
    IDomainEntityModifiable,
    IDomainEntityActivatable, 
    IDomainEntityNameable { ... }

我的想法是,LazyRepo使用实现IRepository来实现{em>实现IDomainEntity的。正如您所看到的,IJobRepository实现IRepository,其JobDomainBaseDomainEntity继承,最终实现IDomainEntity

为了我的钱,这个应该用于设置LazyRepo类。

有人可以向我解释为什么我会收到此错误吗? 类型&#39; IJobRepository&#39;不能用作类型参数&#39; TRepo&#39;通用类型或方法&#39; LazyRepo&#39;。来自&#39; IJobRepository&#39;没有隐式引用转换。到&#39; IRepository&#39;

2 个答案:

答案 0 :(得分:3)

我认为这是contravariancecovariance的概念所在。

  

协变接口允许其方法返回比接口中指定的类型更多的派生类型。逆变接口允许其方法接受比接口中指定的类型少的派生类型的参数。

来源:https://msdn.microsoft.com/en-us/library/dd465120.aspx

您可以使用inout关键字解决此问题:

public interface IRepository<out T> : ...

(来源:https://msdn.microsoft.com/en-us/library/dd997386.aspx

答案 1 :(得分:0)

试试这个:

public class ServiceCodeController : ControllerBase {
    // the red squiggly under IJobRepository is saying it's not convertible
    private LazyRepo<IJobRepository, JobDomain> _domainRepo2; 
}

public class LazyRepo<TRepo, TDomain> where TRepo : IRepository<TDomain> where TDomain : IDomainEntity {  }

通过将TDomain指定为约束到IDomainEntity的通用参数并将TRepo约束到TDomain的IRepository,您可以提供编译器将IJobRepository和JobDomain解析为LazyRepo的参数所需的所有信息。这提供了使用差异的替代方法。

问题必须处理IRepository<IDomainEntity>!= IRepository<JobDomain>这一事实。这是在SO上讨论的经典水果碗问题。但是,如果将通用参数替换为IDomainEntity,则可以完全限定TRepo for LazyRepo的运行时定义。

为了完整性,以下是编译代码的修改版本:

public class ControllerBase {}
public interface IDomainEntity {}
public interface IDomainEntityModifiable {}
public interface IDomainEntityActivatable {}
public interface IDomainEntityNameable {}
public interface IListRepository {}
public interface IRepositoryRead<out TDomain> where TDomain : IDomainEntity {}
public interface IRepositoryCreate<out TDomain> where TDomain : IDomainEntity {}
public interface IRepositoryDelete<out TDomain> where TDomain : IDomainEntity {}
public interface IRepositoryUpdate<out TDomain> where TDomain : IDomainEntity {}
public class ServiceCodeController : ControllerBase 
{
    private LazyRepo<IJobRepository, JobDomain> _domainRepo2; 
}

public class LazyRepo<TRepo, TDomain> where TRepo : IRepository<TDomain> where TDomain : IDomainEntity {  }

public interface IJobRepository : IRepository<JobDomain>, IListRepository {  }

public interface IRepository<out T> : IRepositoryRead<T>, 
    IRepositoryCreate<T>, 
    IRepositoryDelete<T>, 
    IRepositoryUpdate<T> 
    where T : IDomainEntity {  }

public class JobDomain : BaseDomainEntity { }

public abstract class BaseDomainEntity : IDomainEntity, 
    IDomainEntityModifiable,
    IDomainEntityActivatable, 
    IDomainEntityNameable {  }