1

Why does the compiler only complain when a method is called in a switch statement for a constant value and why is it the error The type name 'A' does not exist in the type?

CS0426 The type name 'A' does not exist in the type 'ClassificationIdentifiers.ClassificationIdentifiersChildren'

public static class ClassificationIdentifiers
{
    public static class ClassificationIdentifiersChildren
    {
        public const string A = "A";
    }
}

switch (classificationFileType)
{
    case ClassificationIdentifiers.ClassificationIdentifiersChildren.A:
        classification = ClassificationIdentifiers.ClassificationIdentifiersChildren.A;
        break;
}

switch (classificationFileType)
{
    case ClassificationIdentifiers.ClassificationIdentifiersChildren.A.ToLower():
        classification = ClassificationIdentifiers.ClassificationIdentifiersChildren.A;
        break;
}

enter image description here

I assume it has something to do with the errors below, "A".ToLower(); or case a.ToLower():.

const string a = "A".ToLower();

switch (classificationFileType)
{
    case a.ToLower():
        classification = ClassificationIdentifiers.ClassificationIdentifiersChildren.A;
        break;
}

CS0133 The expression being assigned to 'a' must be constant

CS0118 'a' is a variable but is used like a type

enter image description here

Ogglas
  • 62,132
  • 37
  • 328
  • 418
  • 1
    There are a number of bits of code there. Which bit do you want explained? As an example `const string a = "A".ToLower();` - well, the error on it is pretty clear. – mjwills Jun 09 '20 at 09:45
  • I suspect https://stackoverflow.com/questions/7593377/switch-case-in-c-sharp-a-constant-value-is-expectedis what you are interested in? Or consider using `if` rather than `switch`. Or consider using a case insensitive `Dictionary` to allow mapping from one value to another. – mjwills Jun 09 '20 at 09:46
  • 3
    String cases must be constant strings, so adding `.ToLower()` is a compiler error. The fact that it complains that "The type name 'A' does not exist in the type 'ClassificationIdentifiers.ClassificationIdentifiersChildren'", rather than complaining that "A constant value is expected" looks like a minor compiler bug – canton7 Jun 09 '20 at 09:47
  • I suspect CS0426 is effectively a variant of CS0118. Since the thing you want is a constant, it knows that everything prior to the last `.` would need to be a type for that to be even possible. Which seems confusing to you, if you don't know it needs a constant, but likely makes sense from the compiler's point of view. – mjwills Jun 09 '20 at 09:52
  • (I asked [on the csharplang gitter](https://gitter.im/dotnet/csharplang?at=5edf5b4030401c1f2445736c)) – canton7 Jun 09 '20 at 10:08
  • @mjwills The question I'm interested in is: `Why does the compiler only complain when a method is called in a switch statement for a constant value and why is it the error The type name 'A' does not exist in the type`. I think @canton7 is correct but it would be nice with an answer with a link to documentation that explains why this particular error is shown. – Ogglas Jun 09 '20 at 10:09
  • It complains for the same reason that CS0118 occurs - because it isn't a constant. And it likely _knows_ it isn't a constant since the thing before the last `.` isn't a type. – mjwills Jun 09 '20 at 10:10
  • @mjwills Yes I think so too but then I would expect `CS0150 A constant value is expected`. – Ogglas Jun 09 '20 at 10:12
  • Why does it matter to you? I am not _defending_ it - just hypothesizing an explanation for it. The error (from the compiler's standpoint) makes sense in the same way that CS0118 makes sense. – mjwills Jun 09 '20 at 10:12
  • @mjwills True but I like to say it anyway, I hope they will write a comment some day. :) It matters because I'm interested and would like to know why the compiler throws this error and not something more obvious like `CS0150`. – Ogglas Jun 09 '20 at 10:15

1 Answers1

5

Your question can be simplified to the following:

public class Test
{
    public const string C = "C";  
    public void M(string s)
    {
        switch (s)
        {
            case C.ToLower():
                break;
        }
    }
}

Which produces:

error CS0246: The type or namespace name 'C' could not be found (are you missing a using directive or an assembly reference?)

The thing in the case label is a pattern, which can be either a constant pattern or a recursive pattern. Constant patterns are things like 1, "test", or the name of a const variable or field.

Recursive patterns get complex, but this one's looking for a ToLower type in a namespace C, which has an empty deconstructor. Something like:

public class Test
{
    public void M(object s)
    {
        switch (s)
        {
            case C.ToLower():
                break;
        }
    }
}

namespace C
{
    public class ToLower
    {
         public void Deconstruct() { }   
    }
}

This is why it's complaining about being unable to find a type or namespace C: it's looking for a ToLower type.


I think the fact that this works is just a quirk of the spec -- I can't see any useful need for it.

canton7
  • 37,633
  • 3
  • 64
  • 77