Question

Est-il possible d'avoir une CollectionElementCollection avec un certain nombre de éléments de collecte de types différents, par exemple:

<collection>
    <add type="MyType1, MyLib" Type1SpecificProp="1" />
    <add type="MyType2, MyLib" Type2SpecificProp="2" />
</collection

J'ai tous les cours requis pour une telle solution:

class MyCollection : ConfigurationElementCollection { }
class MyElement : ConfigurationElement { }
class MyType1 : MyElement { }
class MyType2 : MyElement { }
...
etc

Mais quand je commence mon application, je reçois la prochaine erreur prévisible:

Attribut non reconnu «Type1Specificprop».

car Type1SpecificProp est défini dans MyType1 ne pas MyElement, en particulier si MyCollection a la méthode suivante:

protected override ConfigurationElement CreateNewElement()
{
    return new MyElement(); // but I want instantiate not the base class but by a type given
}

IE Renvoie la classe de base ainsi OnDeserializeUnrecognizedAttribute() chez l'enfant classé ne sont jamais appelés.

La question est donc: comment laisser les classes enfants à résoudre des éléments inconnus par eux-mêmes?

Était-ce utile?

La solution 2

Microsoft.Practices.EnterpriseLibrary.Common.Configuration.PolymorphicConfigurationElementCollection<T> De ENTLIB5, faites ce travail comme un charme.

Autres conseils

J'ai également regardé cela. PolymorphicConfigurationElementCollection<T> semble déprécié. Edit: Ce n'est pas le cas, voir le commentaire de 'Abatishchev' ci-dessous, je reliais juste une ancienne version.

La solution de Rest Wing était prometteuse mais a malheureusement nécessité invoquer des méthodes internes résidant dans un autre espace de noms. Bien que cela soit possible via la réflexion, il ne recevra pas de prix pour coder la beauté dans ce cas.

J'ai également creusé dans la source avec réflexion et j'ai trouvé la solution suivante:

[ConfigurationCollection(typeof(ElementBaseConfig), CollectionType=ConfigurationElementCollectionType.BasicMap)]
public class MyTypesConfigCollection : ConfigurationElementCollection
{
    protected override ConfigurationElement CreateNewElement()
    {
        // Not used but function must be defined
        return null;
    }

    protected override object GetElementKey(ConfigurationElement element)
    {
        return element;
    }

    protected override ConfigurationElement CreateNewElement(string elementName)
    {
        switch (elementName)
        {
            case "mytype1":
                return new MyType1Config();

            case "mytype2":
                return new MyType2Config();

            default:
                throw new ConfigurationErrorsException(
                    string.Format("Unrecognized element '{0}'.", elementName));
        }
    }

    protected override bool IsElementName(string elementName)
    {
        // Required to be true
        return true;
    }

    public override ConfigurationElementCollectionType CollectionType
    {
        get { return ConfigurationElementCollectionType.BasicMap; }
    }
}

Le remplacement de la collectionType est requis, même si cela a été spécifié via l'attribut en haut. Lorsqu'il n'est pas remplacé, la classe de base 'CollectionType fait toujours référence à `` AdDreMoveClearmap' 'qui ne déclenchera pas la fonction `` CreateEwElement (String ElementName)', c'est sa variante sans paramètre 'CreenEmElement ()'. Pour la même raison, la fonction IseElementName écrasée doit être renvoyé vrai.

Notez que j'ai créé un élémentBaseConfig qui est la classe de base de MyType1Config et MyType2Config dans laquelle vous pouvez définir certains attributs partagés.

Une instance de type spécifique (MyType1 et MyType2) doit être créé pour que les classes d'enfants résolvent par elles-mêmes des éléments ou des attributs inconnus.

Depuis le CreateNewElement La méthode ne donne aucune information sur les attributs d'un élément, ce qui n'est pas un lieu où un type d'instanciation spécifique peut se produire.

Après avoir creusé via le réflecteur, on vient de la pile d'appels partielle suivante:

VariantCollection.MyCollection.CreateNewElement()
System.Configuration.ConfigurationElementCollection.CallCreateNewElement()
System.Configuration.ConfigurationElementCollection.OnDeserializeUnrecognizedElement(string elementName, XmlReader reader)

La OnDeserializeUnrecognizedElement la méthode peut être remplacée dans MyCollection classe afin de créer une instance de type spécifique. Au lieu d'utiliser le paramètre sans paramètre CallCreateNewElement Méthode, utilisez une nouvelle qui reçoit XmlReader:

  1. Attribut de lecture type (assurer son existence et sa validité).
  2. Créez un nouvel élément de type spécifié.
  3. Appel internal virtual void AssociateContext( BaseConfigurationRecord configRecord ) méthode de System.Configuration.ConfigurationElement sur l'élément.
  4. Appel internal void CallInit() méthode de System.Configuration.ConfigurationElement sur l'élément.
  5. Retourner l'élément préparé.

BTW, s'il n'y aura pas trop d'éléments de collecte différents, pensez à utiliser quelque chose comme:

<myType1Collection>
    <add Type1SpecificProp="1" />
</myType1Collection>
<myType2Collection>
    <add Type2SpecificProp="2" />
</myType2Collection>

De cette façon, vous pouvez éviter de lancer les articles de MyCollection à un type spécifique.

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