0

See the code below:

public class CustomList : List<string>
{ }

public class BaseService
{
    public BaseService(KeyValuePair<List<string>, string> p1)
    { }
}
public class DerivedService : BaseService
{
    public DerivedService(KeyValuePair<CustomList, string> p1) : base(p1)
    { }
}

I have a compilation error in base(p1): The compiler cannot cast KeyValuePair<CustomList, string> to KeyValuePair<List<string>, string>

(I used types KeyValuePair and List to simplify the example, but in my case, they are generic types that are not part of the framework).

I managed to refactor the code differently, but I'm still curious: it seems to me that it safe to do the cast in this case. Why does the compiler refuse it? This is also surprising because if I replace KeyValuePair with an interface with the covariance out keyword (IMyInterface<out T1, T2>), it compiles.

LPLN
  • 475
  • 1
  • 6
  • 20
Xav987
  • 1,182
  • 1
  • 15
  • 17
  • Does your custom List inherit from IList or sth? How do you expect to be able to automatically converrt to List? – panoskarajohn Dec 13 '19 at 14:46
  • 2
    `KeyValuePair` and `KeyValuePair, string>` are different types – Pavel Anikhouski Dec 13 '19 at 14:51
  • There´s usually no need to even inherit from `List`. Anyway what you want to achieve isn´t possible, because co-variance works only on interfaces (that´s why it compiles for you with`IMyInterface`). – MakePeaceGreatAgain Dec 13 '19 at 14:57
  • For that to work `KeyValuePar` would have to be co-variant on the `TKey` but it is not because classes cannot be variant on generic types, you would need an interface type for that instead. – juharr Dec 13 '19 at 14:59
  • 1
    Imagine that **would work**: `public BaseService(KeyValuePair, string> p1) { p1.Key = new AnotherListThatAlsoDerivesFromListString() }`. [Don´t put giraffes and lions together](https://stackoverflow.com/questions/2033912/c-sharp-variance-problem-assigning-listderived-as-listbase). – MakePeaceGreatAgain Dec 13 '19 at 15:01
  • @HimBromBeere But `Key` is readonly. The real issue is that variance isn't allowed on classes. – juharr Dec 13 '19 at 15:22
  • @juharr I know. But `KeyValuePair` is a `struct`, if we want to be pedantic. – MakePeaceGreatAgain Dec 13 '19 at 15:29
  • My question is more about why the framework does not allow to do it, not really how I can do it. @HimBromBeere partially respond to my question. Also, I found very usefull information on this conversation : https://stackoverflow.com/questions/2733346/why-isnt-there-generic-variance-for-classes-in-c-sharp-4-0/2734070#2734070 – Xav987 Dec 16 '19 at 14:44

1 Answers1

0

The only way is to replace KeyValuePair with interface with covariant generic argument:

    public class CustomList : List<string>
    { }

    public class BaseService
    {
        public BaseService(IKeyValuePair<List<string>, string> p1)
        { }
    }
    public class DerivedService : BaseService
    {
        public DerivedService(IKeyValuePair<CustomList, string> p1) : base(p1)
        { }
    }

    public interface IKeyValuePair<out TKey, out TValue>
    {
         TKey Key {get;}
         TValue Value {get;}
    }
Igor Buchelnikov
  • 505
  • 4
  • 14