Casting generic class type to its base class fails [duplicate]

我怕爱的太早我们不能终老 提交于 2021-01-28 02:31:43

问题


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

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.


回答1:


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.

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

See https://docs.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance for a more detailed explanation of covariance.



来源:https://stackoverflow.com/questions/49206089/casting-generic-class-type-to-its-base-class-fails

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!