c# 3.0强制转换接口泛型类型

本文关键字:转换 接口 泛型类型 | 更新日期: 2023-09-27 18:10:15

给定这些基类和接口

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>(); }
    }

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

protected override IStatisticsRepository<IStatistic> Repository
    {
      get { return (IStatisticsRepository<IStatistic>)RepositoryFactory.AverageCheckTimeRepository; }
    }

我如何将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; }
    }

c# 3.0强制转换接口泛型类型

不,c# 3不支持泛型方差。c# 4可以,但是你必须声明IStatisticsRepositoryT中是协变的:

public interface IStatististicsRepository<out T> : IRepository<T>
    where T : IStastistic

方差通常是不安全的——它取决于如何使用泛型类型参数。c# 4支持引用类型的类型参数的协方差和逆变,但只有当涉及的泛型类型是接口或委托时,并且只有当类型参数在接口/委托中以适当的方式使用时。

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

void Save(string id, T value);

那么它就不安全了,因为你可以这样写:

IStatisticsRepository<IStatistic> repo = RepositoryFactory.AverageCheckTimeRepository;
IStatistic foo = new SomeOtherStastisticType();
repo.Save("Foo", foo);

这将试图将SomeOtherStatisticType值保存在AverageCheckTimeRepository中,这违反了类型安全。只有当类型T的值只从接口"输出"时,才可以在T中使接口协变。(请注意,这句话的确切含义有些模糊……)

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