C# 3.0 转换接口泛型类型

发布于 2024-12-07 15:47:53 字数 1829 浏览 0 评论 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>(); }
    }

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

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

如何将 IAverageCheckTimeRepository 的实例转换为 IStatisticsRepository(我假设它已经是) ?


好吧,我已经做了这些改变......这让我想知道我是否一开始就过度使用了泛型

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

Given these base classes and interfaces

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

Why does AverageCheckTime's implementation throw an invalid cast exception:

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

How do I cast an instance of IAverageCheckTimeRepository as an IStatisticsRepository<IStatistic> which I assumed it already was?


OK, I've made these changes...which makes me wonder if I've gone over the top with the generics in the first place

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

两仪 2024-12-14 15:47:53

不,C# 3 不支持通用方差。 C# 4 可以,但您必须声明 IStatisticsRepositoryT 中是协变的:

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

方差一般来说并不安全 - 这取决于如何实现使用泛型类型参数。 C# 4 支持引用类型的类型参数的协变和逆变,但仅当涉及的泛型类型是接口或委托时,并且仅当类型参数在接口/委托中以适当的方式使用时。

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

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 的 有关该主题的博客系列

No, C# 3 does not support generic variance. C# 4 does, but you would have to declare that IStatisticsRepository is covariant in T:

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

Variance isn't safe in general - it depends on how the generic type parameter is used. C# 4 supports both covariance and contravariance for type arguments which are reference types, but only when the generic type involved is an interface or a delegate, and only when the type parameter is used in the appropriate way within the interface/delegate.

Without seeing the declaration for IRepository<T>, we can't tell whether or not it's safe. For example, if IRepository<T> contains a method like this:

void Save(string id, T value);

then it wouldn't be safe, because you'd be able to write:

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

That would be trying to save a SomeOtherStatisticType value in an AverageCheckTimeRepository, which violates type safety. It's only safe to make the interface covariant in T if values of type T only come "out" of the interface. (There are some wrinkles around exactly what that means, mind you...)

For a lot more information on this, see Eric Lippert's blog series on the topic.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文