views:

261

answers:

3

Consider the following code:


    class Program
    {
        static Program() {
            Program.program1.Value = 5;
        }

        static List values = new List();
        int value;
        int Value
        {
            get { return value; }
            set { 
                this.value = value;
                Program.values.Add(this);
            }
        }

        static Program program1 = new Program { value = 1 };
        static Program program2 = new Program { value = 2 };
        static Program program3 = new Program { value = 3 };

        static void Main(string[] args)
        {
            if (Program.values.Count == 0) Console.WriteLine("Empty");
            foreach (var value in Program.values)
                Console.WriteLine(value.Value);
            Console.ReadKey();
        }
    }

It prints only the number 5, and if removed the code in the static constructor, it prints "Empty".

Is there a way to force static fields to be initialized even whether not used yet?

I need to have a static property named Values with returns all instances of the reffered type.

I tried some variations of this code and some works for some types but doesn't for others.

EDIT: THE SAMPLE ABOVE IS BROKEN, TRY THIS ONE:


    class Subclass {
        static Subclass()
        {
            Values = new List>();
        }
        public Subclass()
        {
            if (!Values.Any(i => i.Value.Equals(this.Value)))
            {
                Values.Add(this);
            } 
        }

        public T Value { get; set; }

        public static List> Values { get; private set; }
    }

    class Superclass : Subclass
    {
        public static Superclass SuperclassA1 = new Superclass { Value = 1 };
        public static Superclass SuperclassA2 = new Superclass { Value = 2 };
        public static Superclass SuperclassA3 = new Superclass { Value = 3 };
        public static Superclass SuperclassA4 = new Superclass { Value = 4 }; 
    }

    class Program
    {
        static void Main(string[] args)
        {
            //Console.WriteLine(Superclass.SuperclassA1); //UNCOMMENT THIS LINE AND IT WORKS
            foreach (var value in Superclass.Values)
            {
                Console.WriteLine(value.Value);
            }
            Console.ReadKey();
        }
    }
+2  A: 

Actually looks you misspelled 'value' -> 'Value' So:

    static Program program1 = new Program { Value = 1 };
    static Program program2 = new Program { Value = 2 };
    static Program program3 = new Program { Value = 3 };

pretty prints more lines

Dewfy
+4  A: 

But you're never setting the property -- instead you're setting the backing field directly, so not going through your logic to add to the static list when creating program1, program2 and program3.

i.e. you need to change:

    static Program program1 = new Program { value = 1 };
    static Program program2 = new Program { value = 2 };
    static Program program3 = new Program { value = 3 };

to:

    static Program program1 = new Program { Value = 1 };
    static Program program2 = new Program { Value = 2 };
    static Program program3 = new Program { Value = 3 };
Rowland Shaw
This is why we don't use the same variable name for a member and a property name!
Travis Gockel
Of course, your code allows you to add the same instance to your list many times, so you might instead want to move the "add to static list" logic to the constructor or just check to see if it's already in the list...
Rowland Shaw
Okay! My sample is broken. I mistyped the Value property by the value field. But sadly it is not what is happening in my actual code.I will replace the sample for another one that is more like my actual code, using the constructor to add the instances to the Values list too.I think it has something to do with what John Skeet describes here: http://msmvps.com/blogs/jon_skeet/archive/2010/01/26/type-initialization-changes-in-net-4-0.aspxThanks anyway!
Rafael Romão
@ Travis "This is why we don't use the same variable name for a member and a property name!" - actually you can use the same name an dit is a very common style in C#, but you would typically make the backing field private and only expose the property as public.
Steve Haigh
@Travis and Steve: I agree with Steve. I really don't like the other, underscored, pattern.
Rafael Romão
@Rafael: So you prefer there to be a logical mistake that isn't a compile time error when you make a subtle typo? Interesting...
Travis Gockel
@Travis: As Steve said, it is only used for private fields, so it only affects the developer of the Type, who must be responsible for what he types.
Rafael Romão
+2  A: 

The answer to your question is 'well, yes'. But one of the two ways of "forcing" it is what you're already doing.

The relevant section in the language spec is 10.11 Static constructors, and specifically:

"The static constructor for a class executes at most once in a given application domain. The execution of a static constructor is triggered by the first of the following events to occur within an application domain:

  • An instance of the class is created.
  • Any of the static members of the class are referenced.

If a class contains the Main method (Section 3.1) in which execution begins, the static constructor for that class executes before the Main method is called. If a class contains any static fields with initializers, those initializers are executed in textual order immediately prior to executing the static constructor."

Lette
Yeah! I have read this in the specification too. But I was hopeful there was another, not oficial, way to do it.Thanks!
Rafael Romão
If there is an unofficial way, I'd like to hear about it! But perhaps one should shy away from such techniques. `Unofficial.Equals(Hack)`?
Lette