views:

175

answers:

5

Yes exactly what I want to do :) At least for a particular class. The problem is, I create a static instance of an object but I don not use it directly. Since I do some operations in the constructor ,like adding the object to a list, the constructor must be invoked at least once before I get the list.

I guess that the compiler just optimizes the unused object.

There must be a simple solution :-/

EDIT

Ok may be I miss something. Let me post my code. I wrote a class for custom enum purpose.

        public class TypeSafeEnum<TNameType, TValueType>
        {
        protected readonly TNameType name;
        protected readonly TValueType value;

        private static List<TypeSafeEnum<TNameType, TValueType>> listEnums = new List<TypeSafeEnum<TNameType, TValueType>>();

        protected TypeSafeEnum(TNameType name, TValueType value)
        {
          this.name = name;
          this.value = value;

          listEnums.Add(this);
        }

        public TNameType Name
        {
          get { return name; }
        }

        public TValueType Value
        {
          get { return value; }
        }

        public static TypeSafeEnum<TNameType, TValueType> GetName(TNameType name)
        {
          TypeSafeEnum<TNameType, TValueType> tse = null;
          for (int i = 0; i < listEnums.Count; i++)
          {
            TypeSafeEnum<TNameType, TValueType> typeSafeEnum = listEnums[i];
            if (EqualityComparer<TNameType>.Default.Equals(typeSafeEnum.name, name))
            {
              tse = typeSafeEnum;            
            }
          }
          return tse;
        }

        public static TypeSafeEnum<TNameType, TValueType> GetValue(TValueType value)
        {
          TypeSafeEnum<TNameType, TValueType> tse = null;
          for (int i = 0; i < listEnums.Count; i++)
          {
            TypeSafeEnum<TNameType, TValueType> typeSafeEnum = listEnums[i];
            if (EqualityComparer<TValueType>.Default.Equals(typeSafeEnum.value, value))
            {
              tse = typeSafeEnum;
            }
          }
          return tse;
        }

        public static TNameType[] GetNames()
        {
          TNameType[] names = new TNameType[listEnums.Count];
          for (int i = 0; i < listEnums.Count; i++)
          {
            TypeSafeEnum<TNameType, TValueType> typeSafeEnum = listEnums[i];
            names[i] = typeSafeEnum.name;
          }
          return names;
        }

        public static TValueType[] GetValues()
        {
          TValueType[] values = new TValueType[listEnums.Count];
          for (int i = 0; i < listEnums.Count; i++)
          {
            TypeSafeEnum<TNameType, TValueType> typeSafeEnum = listEnums[i];
            values[i] = typeSafeEnum.value;
          }
          return values;
        }
        }


        public abstract class StringEnum : TypeSafeEnum<string, int>
        {
            protected StringEnum(string name, int value) : base(name, value)
            {
            }
        }


        public sealed class FileOptionEnum : StringEnum
        {
            public static readonly FileOptionEnum Name = new FileOptionEnum("Name", 0);
            public static readonly FileOptionEnum Extension = new FileOptionEnum("Extension", 1);
            public static readonly FileOptionEnum Size = new FileOptionEnum("Size", 2);
            public static readonly FileOptionEnum LastModified = new FileOptionEnum("Last Modified", 3);
            public static readonly FileOptionEnum LastOpened = new FileOptionEnum("Last Opened", 4);
            public static readonly FileOptionEnum Created = new FileOptionEnum("Created", 5);

            public FileOptionEnum(string name, int value) : base(name, value)
            {
            }
        }

Here is how I use it:

        // if I omit this line it returns me empty array
        FileOptionEnum @enum = FileOptionEnum.Name;
        string[] names = FileOptionEnum.GetNames();
        cbFileOptions.Items.AddRange(names);
+2  A: 

You can simply write

new YourObject();

This will not be optimized away.
However, unless the class's constructor saves itself somewhere (eg, adding the object to list or static field, or adding an event handler to something else), the object will probably be garbage-collected right away.

SLaks
+2  A: 

First of all, please verify that the compiler indeed does optimize the code away. Chances are, it really doesn't: if your constructor call has side effects, the compiler doesn't really have the right to get rid of it.

And if it actually does get optimized away, you can use the GC.KeepAlive method to guarantee that the object remains:

GC.KeepAlive( new MyObj() );

This method doesn't really do anything - it has empty body. But it's special in a way that it can't be optimized out. So it you call it with some argument, then that argument also can't be optimized out.

Fyodor Soikin
This will leak memory.
SLaks
@SLaks: Why will it leak memory? Using the keep-alive statement seems silly. Why try to keep a new object alive when the call actually signals the GC that the newly created object can be reclaimed. Is that why it will "leak memory"?
AMissico
Because the object will _never_ be collected. Depending on what the object is and what it does, that may or may not be a problem.
SLaks
Sorry to sound persistent, but trying to understand. I never needed to use keep-alive. Why will it never be collected? Remarks sections states, "The KeepAlive method performs no operation and produces no side effects other than extending the lifetime of the object passed in as a parameter." So passing a new object does nothing. Does this fool the GC in keeping the object alive forever?
AMissico
@Slaks - `KeepAlive` only acts as an opaque method. Once outside of that it does nothing. I'd argue that in this case `KeepAlive` **does nothing**. Typical use of `KeepAlive` is when you init a var at the top of a method (a `Mutex` for example) that you don't ever touch again, but you **really** don't want to be garbage-collected until the method exits. The `KeepAlive` counts as a read against the variable, therefore the value must be preserved. Otherwise, references from variables that aren't read past the stack position are potentially eligible for collection.
Marc Gravell
I misunderstood `KeepAlive`; I retract my comment. Thank you for enlightening me.
SLaks
@Marc Gravell: "KeepAlive does nothing" is true, of course, but please read my first paragraph. The asker is somehow sure that his object creation code is being optimized away. I'm sure that it isn't the case, and that is what the first paragraph is about. But if it were the case, as the asker claims, then KeepAlive would definitely help. Don't you agree?
Fyodor Soikin
A: 

If you are just using some static functionality, why use an instance at all? Create a static class, and have a static 'Initialize()' method that you can call to set up your object.

Steve Mitcham
+1  A: 

Your idea will not work.

The static List<TypeSafeEnum<TNameType, TValueType>> listEnums field will be shared by all TypeSafeEnum classes that have the same name and value types.

To solve that problem, add a parameter for the actual enum class, like this:

public class TypeSafeEnum<TEnum, TName, TValue> where TEnum : TypeSafeEnum<TEnum, TName, TValue>

(You can then replace all of your TypeSafeEnum<...> fields and parameters with TEnum)

I'm pretty sure that this will also solve your actual question.
Since the base TypeSafeEnum class now references the inherited enum class, the inherited class' static constructor will run, initializing the values.

SLaks
I see. thanx. So what do you suggest?
Heka
OK list is now working correctly but the actual problem still remains. :(FileOptionEnum.GetNames() still gives an empty list if FileOptionEnum.Name is not called manually.
Heka
You could use reflection in a static constructor in the base class.
SLaks
A: 

Static members are not guaranteed to be initialized until you attempt to explicitly access them. You can get around this by creating an explicit static constructor (to avoid beforeFieldInit behavior) and explicitly access a static method (like a dummy Init method) to force static initialization.

Dan Bryant