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>(); }
}
为什么 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
不,C# 3 不支持通用方差。 C# 4 可以,但您必须声明
IStatisticsRepository
在T
中是协变的:方差一般来说并不安全 - 这取决于如何实现使用泛型类型参数。 C# 4 支持引用类型的类型参数的协变和逆变,但仅当涉及的泛型类型是接口或委托时,并且仅当类型参数在接口/委托中以适当的方式使用时。
如果没有看到
IRepository
的声明,我们无法判断它是否安全。例如,如果IRepository
包含这样的方法:它不会是安全的,因为您可以编写:
那么 将
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 inT
: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, ifIRepository<T>
contains a method like this:then it wouldn't be safe, because you'd be able to write:
That would be trying to save a
SomeOtherStatisticType
value in anAverageCheckTimeRepository
, which violates type safety. It's only safe to make the interface covariant inT
if values of typeT
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.