Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Enum VS Nullable Property name conflict

There are this, this and this questions about Enum VS Property name conflicts.

My question is not about the naming conventions, instead I'd like to know how to solve the name conflict demonstrated in the code below:

namespace Test
{
    public class Person
    {
        // 1)
        // Gender? Gender { get; set; }

        // 2)
        Gender Gender { get; set; }

        public Person ()
        {
            // 1 - Error CS1061: Type `Test.Gender?' does not contain a definition for `Male' and no extension method `Male' of type `Test.Gender?' could be found (are you missing a using directive or an assembly reference?) (CS1061) (Test)
            // 2 - OK
            Gender = Gender.Male;
        }
    }

    public enum Gender
    {
        Male = 1,
        Female
    }
}

If I declare the property as in 2) Gender Gender { get; set; } the code compiles successfully, however, if I declare as in 1) Gender? Gender { get; set; } (commented in the code above) i get the error

Error CS1061: Type `Test.Gender?' does not contain a definition for `Male' and no extension method `Male' of type `Test.Gender?' could be found (are you missing a using directive or an assembly reference?) (CS1061) (Test)

Why does it happen ?

like image 381
Eduardo Coelho Avatar asked Jan 14 '23 11:01

Eduardo Coelho


2 Answers

Gender? means Nullable<Gender>, this means that when you write Gender.Male the compiler thinks you are trying to invoke a getter on a property called Male on the Nullable<Gender> instance, i.e. Gender is interpretted as a read of the this.Gender property and Male as the read of a property called Male upon the result of that.

The compiler does not identify case (2) as an error as enums cannot have methods so the only resolution that makes sense is for the symbol is the enum itself.

You can fix this by increasing the name qualification:

namespace Acme.Fruits.Banana
{
    ...
    public Person()
    {
        Gender = Banana.Gender.Male
    }
    ...
}
like image 120
Paul Ruane Avatar answered Jan 23 '23 04:01

Paul Ruane


A property or local variable has precedence over a type/enum, this means that if one declares a variable or property with the same name as a type/enum the compiler will resolve any usage of the identifier as the variable/property.

public class Test
{
     public static void SomeMethod(){}
}

public static void Main()
{
     Test.SomeMethod();//ERROR... cannot use variable before declaring it.
     object Test = new object();
     Test.SomeMethod();//ERROR... object does not have a method SomeMethod
}

The only exception to this rule is if the property/variable has the same name as its own type, in which case the compiler allows it to access static members.

public class Test
{
     public static void SomeMethod(){}
}

public static void Main()
{         
     Test Test = new Test();
     Test.SomeMethod();//Works
}

However a nullable type is not the same as the type it encloses, instead the name is in the form of Nullable<T>, and there is only an implicit cast between the two, therefore in the case of a nullable the compiler will no longer allow access to the enum members or static properties.

public struct Test
{
     public static void SomeMethod(){}
}

public static void Main()
{         
     Test? Test = new Test();
     Test.SomeMethod();//ERROR... Test does not have method SomeMethod
}

In a similar fashion it has to be the typed declarion of the variable as the compiler needs to be about it, the following will not work for example:

public class Test
{
     public static void SomeMethod(){}
}

public static void Main()
{         
     object Test = new Test();
     Test.SomeMethod();////ERROR... object does not have a instance method SomeMethod
}
like image 40
yoel halb Avatar answered Jan 23 '23 03:01

yoel halb