none
I do not see variable in identical partiall class situated to different project file RRS feed

  • Question

  • Hello,

    I have program.cs file and ErrorCodes.cs file and identical partial class MYCLASS in both of them, but intellisence does not see the variable from ErrorCodes.cs in program.cs - see picture below. Can someone help me ?

    J.

    Monday, October 1, 2018 1:20 PM

Answers

  • This is a field lifetime issue. Your MYCLASS type is a regular class. To use any member within it you have to instantiate it first. 

    MYCLASS instance = new MYCLASS();
    
    uint errorCode = instance.ERROR_0x100;

    At the point of creation the static constructor (cctor) is run (if it hasn't run yet) the fields are initialized if they have field initializer expressions and then the constructor (ctor) is run. It isn't until the ctor runs that the fields are considered initialized. Therefore you cannot reference a field in another field's initializer expression because the fields aren't guaranteed to be initialized in any particular order. The ctor is the first time you can use a field's value. That is the error you're getting here. ERROR_0x100 is not yet "defined" so you cannot reference it yet.

    Static fields are initialized before the static constructor (cctor) is called and therefore can be referenced by field initializers.

    class MYCLASS
    {
       public uint instanceField = 1;
      
       //Compiler error, field not "defined" yet
       //public uint instanceFieldReference = instanceField;
    
       //Static fields are initialized before cctor
       public static uint staticField = 2;
    
       //Allowed because static fields are initialized before any instance fields 
       public uint staticFieldReference = staticField;
    }

    Interestingly enough static fields can reference other static fields. This results in undefined behavior because static fields aren't initialized in any particular order. But the compiler allows static fields in init expressions so it allows it anyway. There was talk years ago about fixing this but there are a couple of boundary cases where it makes sense so it is allowed. Still it is recommend you review such code carefully.

    Finally a field can be a const. Const fields are glorified literals so they can be referenced by any code because their value is set at compilation time. Hence they are always valid. In your very specific example you should really make your field const because: a) it is clearly an error code that shouldn't change, and b) it would prevent someone from changing the value to something else which makes your error name wrong.

    class MYCLASS
    {
        public const uint ERROR_0x100 = 0x100;
        public uint myerr = ERROR_0x100;       
    }

    In general you should not expose fields publicly. Use properties to expose the data from a class unless the field is const or readonly. This gives you control over the lifetime and contents of the data and flexibility with controlling how it works. As an example you could have worked around the original error by simply using a property as well. Note that you'd still have the issue of your field not being const but whatever.

    class MYCLASS
    {
        //Should be const so you cannot change the value
        public uint ERROR_0x100 = 0x100;
    
        //Using a property gives you access to the fields because
        //a property runs after the instance is created
        public uint myerr => ERROR_0x100;       
    }

    Also note that I wouldn't recommend the approach of using partial classes here. It doesn't serve the purpose you're trying to use it for. Partial classes should be used to take a class that is large and break it up into smaller pieces when using separate types isn't an option.

    Also note that if you have a type that consists of nothing but const or static members should probably be static as well. So to finish the discussion, it appears your MYCLASS (which should be Pascal cased) at this point meets that criteria so I'd just use a static class but if you expand the functionality then using a regular class would be better. I prefer to put my error codes into a standalone type.

    public static class ErrorCodes
    {
       public const uint BadId = 0x100;
    
       public const uint BadCode = 0x101;
    }
    
    public class MyClass
    {
       public uint ErrorCode { get; set; }
    }
    
    //usage
    var instance = new MyClass();
    instance.ErrorCode = ErrorCodes.BadId;


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by Jerry.Mouse Monday, October 1, 2018 4:47 PM
    Monday, October 1, 2018 3:26 PM
    Moderator