c#3.0转换接口泛型类型

jen*_*ent 1 c# generics casting c#-3.0

给定这些基类和接口

public abstract class Statistic : Entity, IStatistic
{
  protected abstract IStatisticsRepository<IStatistic> Repository {get;}

...

public class AverageCheckTime : Statistic

...

public interface IStatisticsRepository<T> : IRepository<T>  where T : IStatistic

...

public interface IAverageCheckTimeRepository : IStatisticsRepository<AverageCheckTime>

...

public class AverageCheckTimeRepository : StatisticRepository<AverageCheckTime>, IAverageCheckTimeRepository

...

public class RepositoryFactory
{
   public static IAverageQueueTimeRepository AverageQueueTimeRepository 
    {
      get { return CurrentServiceLocator.GetInstance<IAverageQueueTimeRepository>(); }
    }
Run Code Online (Sandbox Code Playgroud)

为什么AverageCheckTime的实现会抛出无效的强制转换异常:

protected override IStatisticsRepository<IStatistic> Repository
    {
      get { return (IStatisticsRepository<IStatistic>)RepositoryFactory.AverageCheckTimeRepository; }
    }
Run Code Online (Sandbox Code Playgroud)

我怎么投的实例IAverageCheckTimeRepository作为IStatisticsRepository<IStatistic>其中我以为这已经是?


好的,我已经做出了这些改变......这让我想知道我是否已经首先使用仿制药进入了顶层

    public interface IStatisticsHelper
      {
        void GenerateStatistics();

        List<IStatistic> BuildReport();
      }

...

    public interface IStatisticsRepository<T> : IRepository<T>, IStatisticsHelper where T : IStatistic
      {

      }

...

    public abstract class Statistic : Entity, IStatistic
      {

        protected abstract IStatisticsHelper Repository { get; }

    ...

public class AverageCheckTime : Statistic
  {
    protected override IStatisticsHelper Repository
    {
      get { return RepositoryFactory.AverageCheckTimeRepository; }
    }
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 5

不,C#3不支持通用差异.C#4确实如此,但你必须声明它IStatisticsRepository是协变的T:

public interface IStatististicsRepository<out T> : IRepository<T>
    where T : IStastistic
Run Code Online (Sandbox Code Playgroud)

方差一般不安全- 它取决于泛型类型参数的使用方式.C#4支持作为引用类型的类型参数的协方差和逆变,但仅当涉及的泛型类型是接口或委托时,并且仅当在接口/委托中以适当的方式使用type参数时.

没有看到声明IRepository<T>,我们无法判断它是否安全.例如,如果IRepository<T>包含这样的方法:

void Save(string id, T value);
Run Code Online (Sandbox Code Playgroud)

那么它会不会是安全的,因为你可以写:

IStatisticsRepository<IStatistic> repo = RepositoryFactory.AverageCheckTimeRepository;
IStatistic foo = new SomeOtherStastisticType();
repo.Save("Foo", foo);
Run Code Online (Sandbox Code Playgroud)

这将是试图保存SomeOtherStatisticType在一个值AverageCheckTimeRepository,这违反了类型安全.T如果类型的值T仅出现在接口之外,那么使接口协变是唯一安全的.(确切地说,这有什么皱纹,请注意......)

有关这方面的更多信息,请参阅Eric Lippert 关于该主题博客系列.