Никогда не поздно узнать что-то новое, и спустя более двух лет я готов ответить на свой вопрос.
Короче говоря: это известная ошибка , и она была исправлена в 2.1.505.2. Подробности ниже.
Об ошибке сообщалось в сентябре 2010 года для Unity 2.0, и она оставалась в фреймворке до выпуска версии 2.1.505.2 в августе 2012 года. Это объясняет, почему мы столкнулись с ней, но не почему мы не смогли отследить отчет об ошибках в Google ...
Вот код, необходимый для воспроизведения проблемы.
Определение одноэлементного класса (обратите внимание, что класс вообще не содержит никаких зависимостей):
public class SingletonClass
{
private static SingletonClass m_Instance;
private SingletonClass()
{
}
public static SingletonClass Instance
{
get
{
if (m_Instance == null)
{
m_Instance = new SingletonClass();
}
return m_Instance;
}
}
}
Фактический BuildUp
Звоните:
UnityContainer container = new UnityContainer();
SingletonClass singleton = container.BuildUp(SingletonClass.Instance);
До версии 2.1.505.0 этот код выдавал либо InvalidOperationException
, либо ResolutionFailedException
. Начиная с версии 2.1.505.2, этот код работает нормально (с моей точки зрения, как и положено).
Интересно знать, что фактическое исправление было сделано путем переписывания фрагмента кода, который я обрисовал в общих чертах в вопросе. Вот как выглядят соответствующие части Microsoft.Practices.ObjectBuilder2.DynamicMethodConstructorStrategy
:
public override void PreBuildUp(IBuilderContext context)
{
...
SelectedConstructor selectedCtor = selector.SelectConstructor(context, resolverPolicyDestination);
GuardTypeIsNonPrimitive(context);
...
}
private static void GuardTypeIsNonPrimitive(IBuilderContext context)
{
var typeToBuild = context.BuildKey.Type;
if (!typeToBuild.GetTypeInfo().IsInterface)
{
if (typeToBuild == typeof(string))
{
throw new InvalidOperationException(
string.Format(
CultureInfo.CurrentCulture,
Resources.TypeIsNotConstructable,
typeToBuild.GetTypeInfo().Name));
}
}
}
Самая важная часть здесь заключается в том, что теперь сторожевой метод GuardTypeIsNonPrimitive
не учитывает конструктор - только сам тип. Я думаю, что это было корнем проблемы.
Тот факт, что это ошибка, отвечает на первый вопрос в посте. Как насчет второго? Как обойти эту проблему? Если вы используете Unity 2.1.505.2 и выше, у вас нет этой проблемы, поэтому наиболее предпочтительным вариантом является обновление вашей версии Unity. Однако, если вам приходится иметь дело с 2.1.505.0 и ниже - есть несколько подходов:
Рефакторинг кода, чтобы избавиться от синглтона, и зарегистрировать тип в контейнере с соответствующим временем жизни, как это предложено Ladislav Mrnka в другом ответе на этот вопрос. В нашем случае это было невозможно, но все же иногда это может быть путь.
Загрузите исходные коды и перекомпилируйте их, изменив реализацию GuardTypeIsNonPrimitive
с версией, опубликованной выше.
Реализуйте собственную инъекцию, например, как метод расширения класса UnityContainer
. Один пример можно найти здесь (сама ссылка устарела, поэтому вместо ссылки на версию веб-архива).
Как всегда правильный выбор зависит от конкретной ситуации.