Activator.CreateInstance找不到构造函数(MissingMethodException)

27

我有一个类,它有以下构造函数

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.Scenarios.Composites.DelayCompositeDesignerVoid .ctor(Vialis.LightLink.Controller.Scenarios.Composites.DelayComposite) param:Vialis.LightLink.Controller.Scenarios.Composites.DelayComposite foo ---->


Leppie,您是正确的。由于某些原因,我在我的 UI 应用程序中引用了组合件程序集...这不是我应该做的事情,因为我是在运行时加载它。以下代码可行:

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

结果是相同的。

Timothy - 我已经修改了我的答案,以传递 typeof(DelayCompositeDesigner) ... 或者也许我仍然缺少拼图的一部分。 - Kev
你能详细说明一下 designerAttribute.Designer 是如何声明的吗? - Kev
蒂莫西 - designerAttribute.Designer 是否声明为类型? - Kev
我曾经遇到过类似的问题,但是后来发现我的构造函数没有被找到,原因是它不是public(糟糕!) - Cameron
10个回答

19

我认为你的调用需要是这样的:

var designer = Activator.CreateInstance(designerAttribute.Designer, new object[] { new DelayComposite(4) });

除非当然,它就是那个意思,否则答案并不明显。


1
我不小心使用了 List<T> 而不是 T[]。谢谢! - ToastyMallows
@ToastyMallows 这也是我的问题。由于Activator.CreateInstance(Type target, param object[] args)获取了一个param数组,它把我的List<object>(意思是参数列表)当作单个参数处理了(该列表被转换为对象并包装在大小为1的数组中)。 - woot ness

18

我认为你正在处理类型不匹配的问题。

很可能是程序集在不同位置被引用,或者它们编译的版本不同。

我建议您遍历ConstructorInfo并在适当的参数上执行paramtype == typeof(DelayComposite)


谢谢!类型不匹配是我的问题。我检查了一下,发现传递给构造函数的参数类型错误(相同的类名,不同的命名空间)。 - Cossens

7
尽管我讨厌类似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));

在Visual Studio的输出窗口中打印了什么?

3

如果无参构造函数不是公共的,那可能会导致这个问题。 - Zyo

3
如果您想调用这个构造函数...
public DelayCompositeDesigner(DelayComposite CompositeObject)

只需使用这个:

var designer = Activator.CreateInstance(typeof(DelayCompositeDesigner), new DelayComposite(4));

或者

var designer = Activator.CreateInstance<DelayCompositeDesigner>(new DelayComposite(4));

designerAttribute.Designer 似乎等于 typeof(DelayCompositeDesigner)。 - VolkerK
Ishmaeel - 当他创建一个DelayCompositeDesigner实例时,他需要使用DelayCompositeDesigner(DelayComposite CompositeObject)。对于给定的示例,CreateInstance()上没有重载。 - Kev
确实:designerAttribute.Designer是那种类型,因为我不知道它将是什么,所以我不能使用= typeof(DelayCompositeDesigner)。 - TimothyP
Kev - CreateInstance的第二个参数是“params”参数。这意味着您可以使用任意数量的附加参数调用它,而无需将它们包装在object[]中。 - Ishmaeel
Ishmaeel - 我猜你在我第一次读到帖子后几秒钟内就更改了答案; 无论如何,我放弃了这个问题,原帖的发布者并没有对问答非常积极回应/公开。 - Kev
@TimothyP - 开帖者的速记方式,比输入姓名更快。 - Kev

1
当我遇到这个问题时,我正在使用一种方法返回参数列表,以插入到Activator.CreateInstance中,它与我尝试创建的对象的构造函数有不同数量的参数。

1

我在回答 SF 上的另一个问题时,发现了一种创建对象实例的方法,而不需要调用构造函数。

System.Runtime.Serialization 命名空间中,有一个函数 FormatterServices.GetUninitializedObject(type) 可以创建一个对象,而不需要调用构造函数。

如果你在 Reflector 中查看该函数,你会发现它正在进行外部调用。我不知道在幕后究竟发生了什么黑魔法。但我已经证明了构造函数从未被调用,但对象已经被实例化。


1
在我的情况下,这段代码在.NET Framework上效果很好,但在.NET Core 3.1上不起作用。它会抛出一个无法捕获的ExecutionEngineException异常。但是当我将目标更改为.NET 5时,它可以完美地工作。希望这能帮助某些人。
Type type = assembly.GetType(dllName + ".dll");
Activator.CreateInstance(type ), new Stream[] { stream };

0
您可以在CreateInstance上使用以下重载:
public static Object CreateInstance(
    Type type,
    Object[] args
)

而在你的情况下,应该是这样的(我想):

var designer = Activator.CreateInstance(
    typeof(DelayCompositeDesigner), 
    new object[] { new DelayComposite(4) } 
);

我已经尝试过这个,但它不起作用。同时,无需创建新的object[]对象。 - TimothyP
我实际上有一个需要新对象[]的情况。我的构造函数中的(单个)参数类型是Tuple<double,double>[],只有当我将其作为单个元素object[]传递时,它才能找到构造函数。 - Han

0

我找到了一个解决问题的方法,我曾经也遇到过同样的问题。

这是我的激活器:

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" });
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接