Подтвердить что ты не робот

InvalidOperationException в режиме выпуска visual studio с момента использования .Net 4.0

У меня возникли проблемы с переносом существующего приложения .NET 3.5 на .NET 4.0. Кодекс не написан сам, поэтому я не знал подробно, почему все так, как есть.

Это Ситуация: Код работает нормально, если приложение запускается из Visual Studio (Release или Debug-Mode не имеет значения), а также если приложение запущено из Debug-папки Проблема заключается в выпуске-развертывании, потому что он не работает с 4.0 (а также в версии 4.5): -/

Это начальный вызов:

someObject.Text = Elements.GetElement(Int16.Parse(cb1.Text));

И вот код:

public class Elements : EnumBase<int, Elements>
{
    public static readonly Elements Element1 = Create("Number 0", 0);
    public static readonly Elements Element2 = Create("Number 1", 1);

    private static Elements Create(string text, int value) 
    {
        return new Elements() { text = text, value = value };
    }

    public static String GetElement(int id)
    {

        // The Following Code safes the day and let the release deploy work fine.
        // It doesn´t matter if the condition becomes true or not to runtime.
        /* 
        if (id == 999999999)
        {
            Elements el = Element1;
        }
        */

        // Release deploy works also fine if you do the following line in a loop instead of linq.
        return BaseItemList.Single(v => v.Value == id).Text; 
    }
}

[Serializable()]
public class EnumBase<T, E> :  IEqualityComparer<E> 
        where E : EnumBase<T, E>
{
    private static readonly List<E> list = new List<E>();
    protected string text;
    protected T value;

    protected static IList<E> BaseItemList
    {
        get
        {
            return list.Distinct(new EnumBase<T, E>(false)).ToList();
        }
    }

    protected EnumBase()
    {
        list.Add(this as E);
    }

    /// <summary>
    /// Constructor for distinct to avoid empty elements in the list
    /// </summary>   
    private EnumBase(bool egal) {}

    public string Text
    {
        get { return text; }
    }

    public T Value
    {
        get { return value; }
    }


    #region IEqualityComparer<E> Member

    // ...

    #endregion
}

Ключ return BaseItemList.Single(v => v.Value == id).Text;. Он выбрасывает InvalidOperationException, потому что в Release public static readonly Elements Element1 = Create("Number 0", 0); и public static readonly Elements Element2 = Create("Number 1", 1); не готовы. В момент исключения BaseItemList пуст (BaseItemList.Count = 0). Я не уверен, почему это произошло в папке bin-формы выпуска, а не в выпуске из визуальной студии. Для тестов я деактивировал "Оптимизировать код" в свойствах проекта, но он не помогает.

Несомненно, конструкция не самая лучшая, но я хочу знать, что отличает в .Net 4.0, который приносит код к более плоскому.

Спасибо за помощь

4b9b3361

Ответ 1

Я считаю, что проблема в том, что вы полагаетесь на статический инициализатор для запуска Elements, несмотря на то, что вы не ссылались на какие-либо поля внутри него. Инициализатор типа в типе, который не имеет статического конструктора, гарантированно запускается только до первого доступа к статическому полю. Раздел 10.5.5.1 спецификации С# 5:

Если в классе существует статический конструктор (§10.12), выполнение инициализаторов статического поля происходит непосредственно перед выполнением этого статического конструктора. В противном случае инициализаторы статического поля выполняются в зависящее от реализации время до первого использования статического поля этого класса.

И раздел 10.12 имеет:

Статический конструктор для замкнутого типа класса выполняется не более одного раза в заданном домене приложения. Выполнение статического конструктора запускается первым из следующих событий в домене приложения:

  • Создается экземпляр типа класса.
  • Ссылка на любой из статических членов типа класса.

Реализация инициализации типа изменена в .NET 4, но это была только деталь реализации - ваш код был сломан раньше, вы просто сделали Не знаю.

Если вы измените свой код, чтобы:

static Elements() {}

в классе Elements, то я считаю, что это сработает - потому что статические конструкторы вынуждают инициализацию типа происходить до момента первого доступа к членству, а не просто "в какой-то момент до первого доступа к полю".

Лично я сомневаюсь в общей схеме, но это немного другое дело.