0

The following code produced a conversion error on line

IName result = newtest.Add<testClass2<testClass>>(t2);

It seems like the code can not read the interface of the internal generic type. Am I using the wrong syntax of is this really a limitation?

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;

namespace UnitTestProject1
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {

            test newtest = new test();

            testClass t1 = new testClass();
            testClass2<testClass> t2 = new testClass2<testClass>();
            IName result = newtest.Add<testClass2<testClass>>(t2);

            Assert.AreEqual(result, t1);
        }


        public interface IName
        {
            public string Name { get; set; }
        }

        public interface ItestClass2<T> where T : IName
        {
            string ToString(T value);
        }

        public class testClass : IName
        {
            public string Name { get; set; }
        }

        public class testClass2<T> : ItestClass2<T> where T : IName
        {
            public string ToString(T value)
            {
                return value.GetType().FullName;
            }
        }


        public class test
        {
            private Dictionary<string, ItestClass2<IName>> store = new Dictionary<string, ItestClass2<IName>>();

            public T Add<T>(T value) where T : ItestClass2<IName>
            {
                this.store.Add(value.GetType().FullName, value);
                return value;
            }
        }

    }
}

The error message is:

Severity    Code    Description Project File    Line    Suppression State
Error   CS0311  The type 'UnitTestProject1.UnitTest1.testClass2<UnitTestProject1.UnitTest1.testClass>' cannot be used as type parameter 'T' in the generic type or method 'UnitTest1.test.Add<T>(T)'. There is no implicit reference conversion from 'UnitTestProject1.UnitTest1.testClass2<UnitTestProject1.UnitTest1.testClass>' to 'UnitTestProject1.UnitTest1.ItestClass2<UnitTestProject1.UnitTest1.IName>'.   UnitTestProject1    C:\Users\kevin\source\repos\UnitTestProject1\UnitTestProject1\UnitTest1.cs  17  Active
kevin
  • 338
  • 2
  • 13
  • Can you share the conversion detail error details? – Trevor Dec 08 '20 at 21:50
  • 3
    `testClass2` doesn't implement `IName` so there's no conversion to it. It's `T` that implements `IName` but that doesn't confer implementation transitively. – madreflection Dec 08 '20 at 21:51
  • @madreflection testClass2's interface is constrained to IName. TestClass implements the IName interface. – kevin Dec 08 '20 at 21:59
  • 1
    No, `testClass2`'s *type argument* (`T`) is so constrained, but your code requires that `testClass2` implements the interface, not that its type argument does. – madreflection Dec 08 '20 at 22:01
  • @madreflection Are you speaking of this line? ``` public class testClass2 : ItestClass2 where T : IName ``` It constrains T to IName and then passes it to the ItestClass2 interface. – kevin Dec 08 '20 at 22:08
  • Yes, and I said as much, but what you're not seeing is that `testClass2` doesn't implement `IName`. You would need something like `testClass2 : IName, ItestClass2 where T : IName`. – madreflection Dec 08 '20 at 22:10
  • 4
    Furthermore, a `testClass2` is not a `testClass2`. It doesn't matter that `testClass` implements `IName`. It's not contravariant. – madreflection Dec 08 '20 at 22:10
  • @madreflection, testClass2 is not an IName and does not implement its properties. It uses IName parameters in its innerworkings. – kevin Dec 08 '20 at 22:33
  • 1
    The issue is the same as with all of the other hundreds, if not thousands, of questions already on Stack Overflow involving the mistaken expectation that a base/derived relationship between two different type parameters confers the same relationship on the generic type where the parameters are used. Other than specific exceptions (e.g. generic type variance for interfaces, where such variance is safe), this is not supported in C#. See duplicate for one of those many questions with answers that explain why classes like `List` and `Dictionary` are invariant. – Peter Duniho Dec 08 '20 at 22:46

0 Answers0