将通用类类型强制转换为其基类失败 [英] Casting generic class type to its base class fails

查看:45
本文介绍了将通用类类型强制转换为其基类失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将泛型转换为继承自它的非泛型类型,但失败.检查以下代码:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆