Activator.CreateInstance не может найти конструктор (MissingMethodException)
У меня есть класс, который имеет следующий конструктор
public DelayCompositeDesigner(DelayComposite CompositeObject)
{
InitializeComponent();
compositeObject = CompositeObject;
}
вместе с конструктором по умолчанию без параметров.
Далее я пытаюсь создать экземпляр, но он работает только без параметров:
var designer = Activator.CreateInstance(designerAttribute.Designer);
Это работает просто отлично, но если я хочу передать параметры, это не так:
var designer = Activator.CreateInstance(designerAttribute.Designer, new DelayComposite(4));
Это приводит к MissingMethodException
:
Тип конструктора Vialis.LightLink.Controller.Scenarios.Composites.DelayCompositeDesigner не найден
Есть идеи здесь?
Проблема в том, что мне действительно нужно передать объект во время строительства.
Вы видите, у меня есть дизайнер, который загружает все типы, которые наследуются от CompositeBase
, Затем они добавляются в список, из которого пользователи могут перетаскивать их в дизайнер. После этого экземпляр перетаскиваемого объекта добавляется в конструктор. Каждый из этих классов имеет определенные свойства, определенные на них:
[CompositeMetaData("Delay","Sets the delay between commands",1)]
[CompositeDesigner(typeof(DelayCompositeDesigner))]
public class DelayComposite : CompositeBase
{
}
Когда пользователь выбирает элемент в конструкторе, он просматривает эти атрибуты, чтобы загрузить конструктор для этого типа. Например, в случае DelayComposite
он загрузит пользовательский элемент управления, который имеет метку и ползунок, которые позволяют пользователю установить свойство "Задержка" DelayComposite
пример.
Пока это работает нормально, если я не передаю параметры конструктору. Дизайнер создает экземпляр DelayCompositeDesigner
и назначает его свойству содержимого WPF ContentPresenter
,
Но так как этот дизайнер должен изменить свойства выбранного DelayComposite
в конструкторе я должен передать этот экземпляр ему. Вот почему конструктор выглядит так:
public DelayCompositeDesigner(DelayComposite CompositeObject)
{
InitializeComponent();
compositeObject = CompositeObject;
}
Предложения приветствуются
@VolkerK
Результат вашего кода такой:
<---- foo Vialis.LightLink.Controller.Scenarios.Composites.DelayCompositeDesignerVoid.ctor () Vialis.LightLink.Controller..LightLink.Controller.Scenarios.Composites.DelayComposite foo ---->
Леппи, ты был прав, я по какой-то причине ссылался на сборку Composites в своем приложении пользовательского интерфейса... это не то, что я должен был сделать, когда загружал его во время выполнения. Следующий код работает:
object composite = Activator.CreateInstance(item.CompositType,(byte)205);
var designer = Activator.CreateInstance(designerAttribute.Designer, composite);
Как вы можете видеть, код не имеет знаний о DelayComposite
тип.
Это решает текущую проблему, но вводит много новых для того, чего я хочу достичь, в любом случае спасибо и всем, кто ответил здесь.
Что касается следующего кода, предложенного несколькими людьми:
var designer = Activator.CreateInstance(
designerAttribute.Designer,
new object[] { new DelayComposite(4) }
);
Activator.CreateInstance
имеет подпись, которая выглядит следующим образом:
Activator.CreateInstance(Type type, params object[] obj)
Поэтому он должен принять мой код, но я попробую предложенный код
ОБНОВИТЬ:
Я попробовал это как предложено:
var designer = Activator.CreateInstance(designerAttribute.Designer, new object[] { new DelayComposite(4)});
Результат тот же.
10 ответов
Я думаю, что вы имеете дело с несоответствием типов.
Скорее всего, на сборку ссылаются в разных местах, или они скомпилированы для разных версий.
Я предлагаю вам пройтись по ConstructorInfo's и сделать paramtype == typeof(DelayComposite)
по соответствующему параметру.
Я думаю, что ваш звонок должен быть:
var designer = Activator.CreateInstance(designerAttribute.Designer, new object[] { new DelayComposite(4) });
Если, конечно, это не так, в этом случае ответ не сразу очевиден.
Хотя я ненавижу printf-подобную отладку...
public static void foo(Type t, params object[] p)
{
System.Diagnostics.Debug.WriteLine("<---- foo");
foreach(System.Reflection.ConstructorInfo ci in t.GetConstructors())
{
System.Diagnostics.Debug.WriteLine(t.FullName + ci.ToString());
}
foreach (object o in p)
{
System.Diagnostics.Debug.WriteLine("param:" + o.GetType().FullName);
}
System.Diagnostics.Debug.WriteLine("foo ---->");
}
// ...
foo(designerAttribute.Designer, new DelayComposite(4));
var designer = Activator.CreateInstance(designerAttribute.Designer, new DelayComposite(4));
Что это печатает в окне вывода визуальной студии?
Если вы хотите назвать этот конструктор...
public DelayCompositeDesigner(DelayComposite CompositeObject)
... просто используйте это:
var designer = Activator.CreateInstance(typeof(DelayCompositeDesigner), new DelayComposite(4));
или же
var designer = Activator.CreateInstance<DelayCompositeDesigner>(new DelayComposite(4));
У меня была похожая проблема, однако моя проблема была из-за видимости конструктора. Это переполнение стека помогло мне:
Создание конструктора с параметрами во внутреннем классе с отражением
Когда я столкнулся с этой проблемой, я использовал метод, который возвращал список параметров для подключения к Activator.CreateInstance, и у него было другое количество аргументов, чем у конструктора объекта, который я пытался создать.
Я обнаружил другой способ создания экземпляра объекта, вообще не вызывая конструктор, отвечая на другой вопрос по SF.
В пространстве имен System.Runtime.Serialization есть функция FormatterServices.GetUninitializedObject(type), которая будет создавать объект без вызова конструктора.
Если вы посмотрите на эту функцию в Reflector, то увидите, что она выполняет внешний вызов. Я не знаю, как на самом деле происходит черная магия под капотом. Но я доказал себе, что конструктор никогда не вызывался, а объект создавался.
В моем случае этот код хорошо работает с .NET Framework, но не работает в .NET Core 3.1. Это бросает
ExecutionEngineException
что неуловимо. Но когда я меняю цель на .NET 5, она работает отлично. Надеюсь, это кому-нибудь поможет.
Type type = assembly.GetType(dllName + ".dll");
Activator.CreateInstance(type ), new Stream[] { stream };
Я нашел решение проблемы, я боролся с той же проблемой.
Вот мой активатор:
private void LoadTask(FileInfo dll)
{
Assembly assembly = Assembly.LoadFrom(dll.FullName);
foreach (Type type in assembly.GetTypes())
{
var hasInterface = type.GetInterface("ITask") != null;
if (type.IsClass && hasInterface)
{
var instance = Activator.CreateInstance(type, _proxy, _context);
_tasks.Add(type.Name, (ITask)instance);
}
}
}
И вот мой класс для активации, обратите внимание, что я должен был изменить параметры конструктора на объекты, единственный способ, которым я мог заставить его работать.
public class CalculateDowntimeTask : Task<CalculateDowntimeTask>
{
public CalculateDowntimeTask(object proxy, object context) :
base((TaskServiceClient)proxy, (TaskDataDataContext)context) { }
public override void Execute()
{
LogMessage(new TaskMessage() { Message = "Testing" });
BroadcastMessage(new TaskMessage() { Message = "Testing" });
}
}
Вы можете использовать следующую перегрузку в CreateInstance:
public static Object CreateInstance(
Type type,
Object[] args
)
И в вашем случае это будет (я думаю):
var designer = Activator.CreateInstance(
typeof(DelayCompositeDesigner),
new object[] { new DelayComposite(4) }
);