Pergunta

Eu tenho uma classe que tem o seguinte construtor

public DelayCompositeDesigner(DelayComposite CompositeObject)
{
    InitializeComponent();

    compositeObject = CompositeObject;  
}

juntamente com um construtor padrão sem parâmetros.

Em seguida eu estou tentando criar uma instância, mas só funciona sem parâmetros:

var designer = Activator.CreateInstance(designerAttribute.Designer);

Isso funciona muito bem, mas se eu quiser passar parâmetros que não:

var designer = Activator.CreateInstance(designerAttribute.Designer, new DelayComposite(4));

Isso resulta em uma MissingMethodException:

Construtor voor tipo Vialis.LightLink.Controller.Scenarios.Composites.DelayCompositeDesigner não foi encontrado

Todas as ideias aqui?


O problema é que eu realmente preciso passar um objeto durante a construção.

Você vê que eu tenho um designer que carrega todos os tipos que herdam da CompositeBase. Estes são então adicionadas a uma lista a partir da qual os usuários podem arrastá-los para um designer. Ao fazê-lo uma instância da arrastado é adicionado ao designer. Cada uma dessas classes têm propriedades personalizadas definidas sobre eles:

[CompositeMetaData("Delay","Sets the delay between commands",1)]
[CompositeDesigner(typeof(DelayCompositeDesigner))]
public class DelayComposite : CompositeBase
{
}

Quando o usuário seleciona um item no designer, ele olha para esses atributos, a fim de carregar um designer para esse tipo. Por exemplo, no caso do DelayComposite seria carregar um controle de usuário que tem um rótulo e um controle deslizante que permite que o usuário defina a propriedade "Delay" da instância DelayComposite.

Até agora esta multa funciona se eu não passar qualquer parâmetro para o construtor. O designer cria uma instância da DelayCompositeDesigner e atribui à propriedade content de um ContentPresenter WPF.

Mas desde que as necessidades de designer para modificar as propriedades do DelayComposite selecionado no designer, eu tenho que passar essa instância para ele. É por isso que os olhares do construtor mentir isto:

public DelayCompositeDesigner(DelayComposite CompositeObject)
{
    InitializeComponent();

    compositeObject = CompositeObject;
}

As sugestões são bem-vindos


@VolkerK

O resultado do seu código é o seguinte:

<---- 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, você estava certo, eu tinha por algum motivo referenciados os compósitos de montagem na minha candidatura UI ... que não é algo que eu deveria ter feito como eu estava carregando-o em tempo de execução. O código a seguir funciona:

object composite = Activator.CreateInstance(item.CompositType,(byte)205);
                    var designer = Activator.CreateInstance(designerAttribute.Designer, composite);

Como você pode ver o código não tem conhecimento do tipo DelayComposite.

Isto resolve o problema atual, mas introduz muitos novos para o que eu quero alcançar, de qualquer forma, obrigado e obrigado a todos que respondeu aqui.


Como para o código a seguir, sugeridas por várias pessoas:

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

O Activator.CreateInstance tem uma assinatura parecida com esta:

Activator.CreateInstance(Type type, params object[] obj)

Por isso, deve aceitar o meu código, mas vou tentar o código sugerido

UPDATE:

Eu tentei isso como sugerido:

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

O resultado é o mesmo.

Foi útil?

Solução

Eu acho que você está lidando com uma incompatibilidade de tipo.

Provavelmente o assembly é referenciado em lugares diferentes, ou eles são compilados com versões diferentes.

Eu sugiro que você percorrer os ConstructorInfo de e fazer um paramtype == typeof(DelayComposite) sobre o parâmetro adequado.

Outras dicas

Gostaria de pensar que a sua chamada seria necessário:

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

A menos, claro, ele é que, caso em que a resposta não é imediatamente óbvio.

Embora eu ódio printf-like depuração ...

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

O que faz isso de impressão na janela de saída do Visual Studio?

Se você quiser chamar isso contructor ...

public DelayCompositeDesigner(DelayComposite CompositeObject)

... é só usar isto:

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

ou

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

Eu tive um problema semelhante, no entanto o meu problema era devido à visibilidade do construtor. Este estouro de pilha me ajudou:

Instanciando um construtor com parâmetros em uma classe interna com reflexão

Eu descobri uma outra maneira de criar uma instância de um objeto sem chamar o construtor em todos enquanto respondendo outra pergunta sobre SF.

No System.Runtime.Serialization namespace existe uma função FormatterServices.GetUninitializedObject (tipo) que irá criar um objeto sem chamar construtor.

Se você olhar para essa função no refletor você vai ver que está fazendo uma chamada externa. Eu não sei como magia negra realmente está acontecendo sob o capô. Mas eu provar a mim mesmo que o construtor nunca foi chamado, mas o objeto foi instanciado.

Você pode usar o seguinte sobrecarga CreateInstance:

public static Object CreateInstance(
    Type type,
    Object[] args
)

E no seu caso seria (eu acho):

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

Eu encontrei uma solução para o problema, eu estava lutando com o mesmo problema.

Aqui está o meu ativador:

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

E aqui está minha classe para ativar, nota que eu tinha que mudar os parâmetros do construtor de objetos, a única maneira que eu poderia fazê-lo funcionar.

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

Quando eu encontrei este problema, eu estava usando um método que retornou a lista de parâmetros de plug-in para Activator.CreateInstance e tinha um número diferente de argumentos que o construtor do objeto que eu estava tentando criar.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top