Share via

Questionable compiler error on the method’s argument, derived from the type of its formal parameter.

Anonymous
2021-01-25T10:34:11.133+00:00

Hello,

I am getting a compiler error, which seems illogical to me.
It would take longer to describe the problem, than to reproduce it.
Just insert, please, a slash after the very first slash in the code below, and the compiler will make the problem obvious.

Could somebody tell me if this is a bug in the compiler or I am missing something, and the compiler works as designed?

using System;
using System.Collections;
using System.Collections.Generic;

namespace TestConsoleApp {
    class CEnumerable<ElemTypeBase> : IEnumerable<ElemTypeBase> where ElemTypeBase : class {
        public IEnumerator<ElemTypeBase> GetEnumerator() { throw new NotImplementedException(); }
        IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); }
    }
    class CElemTypeBase { }
    class CElemTypeDerived : CElemTypeBase { }
    class Program {
        /* // To see the problem, insert a slash after the very first slash in this line and compile.
        // Why the line below causes problems,
        static public void MethodElemEnumArg(CEnumerable<CElemTypeBase> enumArg) { } // Problematic signature.
        /*/ // while the next line does not?
        static public void MethodElemEnumArg(IEnumerable<CElemTypeBase> enumArg) { }
        //*/
        static public void MethodElemArg(CElemTypeBase elemArg) { }
        static void Main() {
            CEnumerable<CElemTypeBase> enumBase = new CEnumerable<CElemTypeBase>();
            CEnumerable<CElemTypeDerived> enumDerived = new CEnumerable<CElemTypeDerived>();
            CElemTypeBase argBase = new CElemTypeBase();
            CElemTypeBase argDerived = new CElemTypeDerived();
            MethodElemArg(argBase);
            MethodElemArg(argDerived); // Surely works.
            MethodElemEnumArg(enumBase);
            MethodElemEnumArg(enumDerived); // Produces compiler error with the problematic signature.
        }
    }
}
Developer technologies | C#
Developer technologies | C#

An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.

0 comments No comments

Answer accepted by question author

Viorel 127K Reputation points
2021-01-25T11:19:41.797+00:00

Try another signature:

static public void MethodElemEnumArg( IEnumerable<CElemTypeBase> enumArg ) { }

Was this answer helpful?

1 person found this answer helpful.

3 additional answers

Sort by: Most helpful
  1. Daniel Zhang-MSFT 9,661 Reputation points
    2021-01-26T06:15:46.73+00:00

    Hi pnn,
    A brief summary of facts about variance in the common language runtime:

    1. Variant type parameters are restricted to generic interface and generic delegate types.
    2. A generic interface or generic delegate type can have both covariant and contravariant type parameters.
    3. Starting in C# 9, covariant return types are supported. An overriding method can declare a more derived return type the method it overrides, and an overriding, read-only property can declare a more derived type.
      More details you can refer to this document.
      Best Regards,
      Daniel Zhang

    If the response is helpful, please click "Accept Answer" and upvote it.

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Was this answer helpful?

    0 comments No comments

  2. Anonymous
    2021-01-25T10:52:54.567+00:00

    The editor has removed a couple of stars from the code (the trick with switch of code segments does not wok). Please use the code below.

    using System;
    using System.Collections;
    using System.Collections.Generic;
    
    namespace TestConsoleApp {
        class CEnumerable<ElemTypeBase> : IEnumerable<ElemTypeBase> where ElemTypeBase : class {
            public IEnumerator<ElemTypeBase> GetEnumerator() { throw new NotImplementedException(); }
            IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); }
        }
        class CElemTypeBase { }
        class CElemTypeDerived : CElemTypeBase { }
        class Program {
            /* // To see the problem, insert a slash after the very first slash in this line and compile.
            // Why the line below causes problems,
            static public void MethodElemEnumArg(CEnumerable<CElemTypeBase> enumArg) { } // Problematic signature.
            /*/ // while the next line does not?
            static public void MethodElemEnumArg(IEnumerable<CElemTypeBase> enumArg) { }
            //*/
            static public void MethodElemArg(CElemTypeBase elemArg) { }
            static void Main() {
                CEnumerable<CElemTypeBase> enumBase = new CEnumerable<CElemTypeBase>();
                CEnumerable<CElemTypeDerived> enumDerived = new CEnumerable<CElemTypeDerived>();
                CElemTypeBase argBase = new CElemTypeBase();
                CElemTypeBase argDerived = new CElemTypeDerived();
                MethodElemArg(argBase);
                MethodElemArg(argDerived); // Surely works.
                MethodElemEnumArg(enumBase);
                MethodElemEnumArg(enumDerived); // Produces compiler error with the problematic signature.
            }
        }
    }
    

    Was this answer helpful?

    0 comments No comments

  3. Karen Payne MVP 35,606 Reputation points Volunteer Moderator
    2021-01-25T10:51:12.643+00:00

    Hello,

    The single / is seen as a math operator in this case. // is a comment and /// is used for marking a class, method or property comment.

    60176-11111111111.png

    These are valid
    60271-11111111111-1.png

    Was this answer helpful?

    0 comments No comments

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.