Visual C# Developer Center > Visual C# Forums > Visual C# General > Advanced method type constraints
Ask a questionAsk a question
 

AnswerAdvanced method type constraints

  • Friday, November 06, 2009 12:24 PMRubVer Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    Hello,

    I have some code that does not compile, but I cannot figure out why. This is an example:

    interface MyType { }
    
    interface MyOtherType {}
    
    class MyTypeImplementation : MyType, MyOtherType {}
    
    interface TestInterface<T>
    {
        S Test<S>() where S : T, MyOtherType;
    }
    
    class TestImplementation : TestInterface<MyType>
    {
        public S Test<S>() where S : MyType, MyOtherType
        {
            return (S)new MyTypeImplementation();
        }
    }
    
    Compilation of TestImplementation.Test<S> fails with CS0030: "Cannot convert type 'MyTypeImplementation' to 'S'".
    However, this is clearly not true since MyTypeImplementation implements both MyType and MyOtherType, satisfying the constraints on S.

    Note that omitting any of the constraints on S does not change the problem.

    Can anybody shed a light on this?

    Thanks,

    Ruben

Answers

  • Friday, November 06, 2009 12:36 PMDavid M MortonMVP, ModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    Here's what your logic is here:

    1. S is a MyType and MyOtherType.
    2. MyTypeImplementation is a MyType and MyOtherType.
    3. Therefore, MyTypeImplementation is S.

    Let's reword this in terms that are easier to understand:

    1. David is a human.
    2. Ruben is a human.
    3. Therefore, David is Ruben.

    That's obviously not true.  I'm not you, just because we're both humans. 

    When you make a generic constraint, you're constraining the type of S to only types that implement those interfaces.  You're not saying that any type that implements those interfaces, by necessity, must be S. 

    Here's some code that might clear it up:

    namespace ConsoleApplication75
    {
        class Program
        {
            static void Main(string[] args)
            {
                TestImplementation imp = new TestImplementation();
                imp.Test<MyOtherImplementation>();

            }

        }

        interface MyType { }

        interface MyOtherType { }

        class MyTypeImplementation : MyType, MyOtherType { }

        class MyOtherImplementation : MyType, MyOtherType { }

        interface TestInterface<T>
        {
            S Test<S>() where S : T, MyOtherType;
        }


        class TestImplementation : TestInterface<MyType>
        {
            public S Test<S>() where S : MyType, MyOtherType
            {
                return (S)new MyTypeImplementation();
            }
        }
    }

    Once I call Test, with MyOtherImplementation as a generic type parameter, then "S" is MyOtherImplementation.  Obviously, MyTypeImplementation is not MyOtherImplementation, which is what the compiler recognizes and prevents with this error.

    I hope that helps.


    Coding Light - Illuminated Ideas and Algorithms in Software
    Coding Light WikiLinkedInForumsBrowser

All Replies

  • Friday, November 06, 2009 12:36 PMDavid M MortonMVP, ModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    Here's what your logic is here:

    1. S is a MyType and MyOtherType.
    2. MyTypeImplementation is a MyType and MyOtherType.
    3. Therefore, MyTypeImplementation is S.

    Let's reword this in terms that are easier to understand:

    1. David is a human.
    2. Ruben is a human.
    3. Therefore, David is Ruben.

    That's obviously not true.  I'm not you, just because we're both humans. 

    When you make a generic constraint, you're constraining the type of S to only types that implement those interfaces.  You're not saying that any type that implements those interfaces, by necessity, must be S. 

    Here's some code that might clear it up:

    namespace ConsoleApplication75
    {
        class Program
        {
            static void Main(string[] args)
            {
                TestImplementation imp = new TestImplementation();
                imp.Test<MyOtherImplementation>();

            }

        }

        interface MyType { }

        interface MyOtherType { }

        class MyTypeImplementation : MyType, MyOtherType { }

        class MyOtherImplementation : MyType, MyOtherType { }

        interface TestInterface<T>
        {
            S Test<S>() where S : T, MyOtherType;
        }


        class TestImplementation : TestInterface<MyType>
        {
            public S Test<S>() where S : MyType, MyOtherType
            {
                return (S)new MyTypeImplementation();
            }
        }
    }

    Once I call Test, with MyOtherImplementation as a generic type parameter, then "S" is MyOtherImplementation.  Obviously, MyTypeImplementation is not MyOtherImplementation, which is what the compiler recognizes and prevents with this error.

    I hope that helps.


    Coding Light - Illuminated Ideas and Algorithms in Software
    Coding Light WikiLinkedInForumsBrowser