Принудительный компилятор C # для создания неиспользуемого экземпляра объекта - PullRequest
4 голосов
/ 02 июня 2010

Да, именно то, что я хочу сделать :) По крайней мере для определенного класса. Проблема в том, что я создаю статический экземпляр объекта, но не использую его напрямую. Поскольку я выполняю некоторые операции в конструкторе, например, добавляю объект в список, конструктор должен быть вызван хотя бы один раз, прежде чем я получу список.

Полагаю, компилятор просто оптимизирует неиспользуемый объект.

Должно быть простое решение: - /

EDIT

Хорошо, может быть, я что-то упустил. Позвольте мне опубликовать мой код. Я написал класс для пользовательских перечислений.

        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)
            {
            }
        }

Вот как я это использую:

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

Ответы [ 5 ]

2 голосов
/ 02 июня 2010

Прежде всего, пожалуйста, убедитесь, что компилятор действительно оптимизирует код. Скорее всего, на самом деле это не так: если ваш вызов конструктора имеет побочные эффекты, компилятор на самом деле не имеет права от него избавиться.

И если он действительно оптимизирован, вы можете использовать метод GC.KeepAlive, чтобы гарантировать, что объект останется:

GC.KeepAlive( new MyObj() );

Этот метод на самом деле ничего не делает - у него пустое тело. Но это особенный способ, которым его нельзя оптимизировать. Так что если вы вызываете это с каким-то аргументом, то этот аргумент также нельзя оптимизировать.

2 голосов
/ 02 июня 2010

Вы можете просто написать

new YourObject();

Это не будет оптимизировано.
Однако, если конструктор класса не сохранит себя где-нибудь (например, добавив объект в список или статическое поле или добавивобработчик события к чему-то еще), объект, вероятно, будет сразу же собран мусором.

1 голос
/ 02 июня 2010

Ваша идея не сработает.

Статическое поле List<TypeSafeEnum<TNameType, TValueType>> listEnums будет общим для всех TypeSafeEnum классов, имеющих одинаковые имена и типы значений.

Чтобы решить эту проблему, добавьте параметр для фактического класса перечисления, например:

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

(Затем вы можете заменить все свои TypeSafeEnum<...> поля и параметры на TEnum)

Я почти уверен, что это также решит ваш актуальный вопрос.
Поскольку базовый класс TypeSafeEnum теперь ссылается на унаследованный класс enum, будет запущен статический конструктор унаследованного класса, инициализирующий значения.

0 голосов
/ 02 июня 2010

Статические члены не гарантируются для инициализации, пока вы не попытаетесь получить к ним явный доступ. Вы можете обойти это путем создания явного статического конструктора (чтобы избежать поведения beforeFieldInit) и явного доступа к статическому методу (например, к фиктивному методу Init) для принудительной статической инициализации.

0 голосов
/ 02 июня 2010

Если вы просто используете статическую функциональность, зачем вообще использовать экземпляр? Создайте статический класс и используйте статический метод «Initialize ()», который можно вызвать для настройки вашего объекта.

...