Question

J'ai une classe qui a le constructeur suivant

public DelayCompositeDesigner(DelayComposite CompositeObject)
{
    InitializeComponent();

    compositeObject = CompositeObject;  
}

avec un constructeur par défaut sans paramètre.

Ensuite, j'essaie de créer une instance, mais cela ne fonctionne que sans paramètres:

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

Cela fonctionne très bien, mais si je veux passer des paramètres, cela ne fonctionne pas:

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

Cela se traduit par un MissingMethodException:

  

Type de constructeur   Vialis.LightLink.Controller.Scenarios.Composites.DelayCompositeDesigner   n'a pas été trouvé

Des idées ici?

Le problème est que j’ai vraiment besoin de passer un objet lors de la construction.

Vous voyez que j’ai un concepteur qui charge tous les types hérités de CompositeBase. Ceux-ci sont ensuite ajoutés à une liste à partir de laquelle les utilisateurs peuvent les faire glisser vers un concepteur. Ce faisant, une instance du traîné est ajoutée au concepteur. Chacune de ces classes possède des propriétés personnalisées définies sur elles:

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

Lorsque l'utilisateur sélectionne un élément dans le concepteur, il examine ces attributs afin de charger un concepteur pour ce type. Par exemple, dans le cas de DelayComposite, il chargerait un contrôle utilisateur comportant une étiquette et un curseur permettant à l'utilisateur de définir le & "Delay &"; propriété de l'instance DelayCompositeDesigner.

Jusqu'à présent, cela fonctionne bien si je ne passe aucun paramètre au constructeur. Le concepteur crée une instance de ContentPresenter et l'assigne à la propriété de contenu d'un WPF Activator.CreateInstance.

Mais puisque ce concepteur a besoin de modifier les propriétés de la sélection <=> dans le concepteur, je dois passer cette instance à elle. C'est pourquoi le constructeur semble mentir ceci:

public DelayCompositeDesigner(DelayComposite CompositeObject)
{
    InitializeComponent();

    compositeObject = CompositeObject;
}

Les suggestions sont les bienvenues

@VolkerK

Le résultat de votre code est le suivant:

  

< ---- 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, vous aviez raison, j'avais pour une raison quelconque fait référence à l'assemblage Composites dans mon application d'interface utilisateur ... ce n'est pas quelque chose que j'aurais dû faire car je le chargeais au moment de l'exécution. Le code suivant fonctionne:

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

Comme vous pouvez le constater, le code n'a pas connaissance du type <=>.

Ceci résout le problème actuel, mais en introduit beaucoup de nouveaux pour ce que je veux réaliser, de toute façon merci et merci à tous ceux qui ont répondu ici.

Comme pour le code suivant, suggéré par plusieurs personnes:

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

Le <=> a une signature qui ressemble à ceci:

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

Donc, il devrait accepter mon code, mais je vais essayer le code suggéré

UPDATE:

J'ai essayé ceci comme suggéré:

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

Le résultat est identique.

Était-ce utile?

La solution

Je pense que vous avez affaire à une incompatibilité de type.

L'assemblage est probablement référencé à différents endroits ou il est compilé avec différentes versions.

Je vous suggère de parcourir les informations ConstructorInfo et de paramtype == typeof(DelayComposite) définir le paramètre approprié.

Autres conseils

Je pense que votre appel doit être:

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

Sauf si, bien sûr, c'est que, dans ce cas, la réponse n'est pas immédiatement évidente.

Bien que je déteste le débogage semblable à 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));

Qu'est-ce que cela affiche dans la fenêtre de sortie de Visual Studio?

Si vous souhaitez appeler ce constructeur ... ... utilisez simplement ceci:

public DelayCompositeDesigner(DelayComposite CompositeObject)

ou

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

J'avais un problème similaire, mais mon problème était dû à la visibilité du constructeur. Ce débordement de pile m'a aidé à:

Instanciation d'un constructeur avec des paramètres dans un classe interne avec réflexion

J'ai découvert un autre moyen de créer une instance d'objet sans même appeler le constructeur en répondant à une autre question sur SF.

Dans l'espace de noms System.Runtime.Serialization , il existe une fonction FormatterServices.GetUninitializedObject (type) qui crée un objet sans appeler le constructeur.

Si vous regardez cette fonction dans Reflector, vous verrez qu’elle passe un appel externe. Je ne sais pas comment la magie noire se passe réellement sous le capot. Mais je me suis prouvé que le constructeur n’a jamais été appelé, mais que l’objet a été instancié.

Vous pouvez utiliser la surcharge suivante sur CreateInstance:

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

Et dans votre cas ce serait (je pense):

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

J'ai trouvé une solution au problème, je me débattais avec le même problème.

Voici mon activateur:

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

Et voici ma classe à activer, notez que je devais changer les paramètres du constructeur en objets, le seul moyen de le faire fonctionner.

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

Quand j'ai rencontré ce problème, j'utilisais une méthode qui renvoyait la liste de paramètres à connecter à Activator.CreateInstance et dont le nombre d'arguments était différent de celui du constructeur de l'objet que je tentais de créer.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top