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, который приносит код к более плоскому.
Спасибо за помощь
Ответы
Ответ 1
Я считаю, что проблема в том, что вы полагаетесь на статический инициализатор для запуска Elements
, несмотря на то, что вы не ссылались на какие-либо поля внутри него. Инициализатор типа в типе, который не имеет статического конструктора, гарантированно запускается только до первого доступа к статическому полю. Раздел 10.5.5.1 спецификации С# 5:
Если в классе существует статический конструктор (§10.12), выполнение инициализаторов статического поля происходит непосредственно перед выполнением этого статического конструктора. В противном случае инициализаторы статического поля выполняются в зависящее от реализации время до первого использования статического поля этого класса.
И раздел 10.12 имеет:
Статический конструктор для замкнутого типа класса выполняется не более одного раза в заданном домене приложения. Выполнение статического конструктора запускается первым из следующих событий в домене приложения:
- Создается экземпляр типа класса.
- Ссылка на любой из статических членов типа класса.
Реализация инициализации типа изменена в .NET 4, но это была только деталь реализации - ваш код был сломан раньше, вы просто сделали Не знаю.
Если вы измените свой код, чтобы:
static Elements() {}
в классе Elements
, то я считаю, что это сработает - потому что статические конструкторы вынуждают инициализацию типа происходить до момента первого доступа к членству, а не просто "в какой-то момент до первого доступа к полю".
Лично я сомневаюсь в общей схеме, но это немного другое дело.