将通用类类型强制转换为其基类失败 [英] Casting generic class type to its base class fails
问题描述
我正在尝试将泛型转换为继承自它的非泛型类型,但失败.检查以下代码:
I am trying to cast a generic type to a non generic one that inherits from it but it fails. Check the code below:
public class Subscription
{
public Subscription(DateTime expiration)
{
Expiration = expiration;
}
public DateTime Expiration { get; set; }
}
public class Subscription<T> : Subscription
{
public T Parameters { get; }
public Subscription(DateTime expiration, T data)
: base(expiration)
{
Parameters = data;
}
}
public class SubscriptionsService
{
private readonly ConcurrentDictionary<int, object> subscriptions;
public SubscriptionsService(ConcurrentDictionary<int, object> subscriptions)
{
this.subscriptions = subscriptions;
}
public void Add<T>(int clientId, DateTime expiration, T parameters)
{
if (!subscriptions.TryGetValue(clientId, out var outObject))
{
Subscription<T> subscription = new Subscription<T>(expiration, parameters);
List<Subscription<T>> clientSubscriptions = new List<Subscription<T>>()
{
subscription
};
subscriptions.AddOrUpdate(clientId, parameters, (k, v) => parameters);
}
else
{
if (outObject is List<Subscription<T>> resourceSubscriptions && resourceSubscriptions.Any())
{
Subscription<T> subscription = resourceSubscriptions.SingleOrDefault(x => x.Parameters.Equals(parameters));
if (subscription == null)
{
subscription = new Subscription<T>(expiration, parameters);
resourceSubscriptions.Add(subscription);
}
else
{
subscription.Expiration = expiration;
}
}
}
}
public void Cleanup()
{
// Iterate through each reportId subscription
foreach (KeyValuePair<int, object> subscriptionKeyValuePair in subscriptions)
{
List<Subscription> subscriptions = (subscriptionKeyValuePair.Value as List<Subscription>);
if (subscriptions == null || !subscriptions.Any())
continue;
foreach (var subscription in subscriptions)
{
if (subscription.Expiration > DateTime.Now)
{
//some code
}
}
}
}
}
当我调用方法Cleanup并遍历键值对时,我试图将字典的值转换为用于将其添加到Add方法的非泛型类型.我添加为List>并尝试将其强制转换为List,以便仅使用Expiration属性,因为我在Cleanup中不需要T参数.结果, List< Subscription>subscriptions
强制转换失败,即使字典中的值不正确,"susbcriptions"也始终为null.
When I call the method Cleanup and iterate through the keyvalue pairs I am trying to cast the values of the dictionary to the non-generic type that I use to add it to the Add Method. I add as List> and try to cast it as List in order to use the only the Expiration property as I dont need the T Parameters inside Cleanup. As a result List<Subscription> subscriptions
casts fails and ```susbcriptions`` is always null even if value in the dictionary is not.
推荐答案
您无法进行此强制转换,因为 List< T>
中的 T
是不变的类型参数.这意味着C#不会将 List< A>
视为 List< B>
的派生类型,即使 A
是从 B派生的
.
You are not able to make this cast because the T
in List<T>
is an invariant type parameter. That means C# does not treat List<A>
as a derived type of List<B>
, even if A
derives from B
.
然而, IEnumerable< T>
具有称为协变量类型参数"的特殊功能.它允许您执行这种类型的转换.这意味着在下面的示例中,带有list1和list2的行将导致编译器错误,但是list3可以正常工作.
However, IEnumerable<T>
has a special feature called a "covariant type parameter". It allows you to do this type of cast. This means that in following example, the lines with list1 and list2 will result in a compiler error, but list3 would work just fine.
public class Program<T>
{
public void Main()
{
IList<Subscription> list1 = new List<Subscription<T>>();
List<Subscription> list2 = new List<Subscription<T>>();
IEnumerable<Subscription> list3 = new List<Subscription<T>>();
}
}
public class Subscription<T> : Subscription
{
}
public class Subscription
{
}
请参见 https://docs.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance 以获得更详细的协方差解释.
See https://docs.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance for a more detailed explanation of covariance.
这篇关于将通用类类型强制转换为其基类失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!