Domanda

È possibile avere una CollectionElementCollection con un numero di CollectionElements diversi per tipo, ad esempio:

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

Ho tutte le classi necessarie per tale soluzione:

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

ma quando avvio la mia applicazione ricevo il prossimo errore prevedibile:

Attributo non riconosciuto "Type1SpecificProp".

Perché Type1SpecificProp è definito in MyType1 non MyElement, soprattutto se MyCollection ha il metodo successivo:

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

cioè.restituisce la classe base in questo modo OnDeserializeUnrecognizedAttribute() nelle classi per bambini non sono mai stati chiamati.

Quindi la domanda è:come consentire alle classi figlie di risolvere da sole elementi sconosciuti?

È stato utile?

Soluzione 2

Microsoft.Practices.EnterpriseLibrary.Common.Configuration.PolymorphicConfigurationElementCollection<T> da EntLib5 Fai questo lavoro come un fascino.

Altri suggerimenti

Ho guardato anche questo. PolymorphicConfigurationElementCollection<T> sembra deprecata . Modifica: non è, vedi il commento di 'Abatishchev' qui sotto, stavo solo collegando una vecchia versione.

La soluzione dell'ala di riposo è stata promettente, ma purtroppo richiedente richiamando metodi interni residenti in un altro spazio dei nomi. Mentre è possibile tramite la riflessione non riceverà prezzi per la codifica della bellezza in questo caso.

Ho scavato anche nella fonte con la riflessione e ha trovato la seguente soluzione:

[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; }
    }
}
.

L'override del collectionTYPE è richiesta, anche se questo è stato specificato tramite l'attributo nella parte superiore. Quando non è sovrascritto la classe base 'CollectionType si riferisce ancora a "addremoveclearmap" che non si attiverà la funzione "CreateNewelement (String ElementName) è la funzione ma è una variante senza parametri" CreateNeMelement () ". Per lo stesso motivo la funzione overwritten iselementname dovrebbe restituire true.

Nota che ho creato un elementbaseconfig che è la classe base di mytype1config e mytype2config in cui è possibile definire alcuni attributi condivisi.

Un'istanza di tipo specifico (MyType1 E MyType2) deve essere creato affinché le classi figlie possano risolvere da sole elementi o attributi sconosciuti.

Dal momento che CreateNewElement Il metodo non fornisce alcuna informazione sugli attributi di un elemento, ovvero non è il luogo in cui può verificarsi l'istanziazione di un tipo specifico.

Dopo qualche ricerca tramite Reflector, si arriva al seguente stack di chiamate parziale:

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

IL OnDeserializeUnrecognizedElement il metodo può essere sovrascritto MyCollection classe per creare un'istanza di tipo specifico.Invece di usare il parametro senza parametri CallCreateNewElement metodo, usane uno nuovo che riceve XmlReader:

  1. Leggi l'attributo type (garantirne l'esistenza e la validità).
  2. Crea un nuovo elemento del tipo specificato.
  3. Chiamata internal virtual void AssociateContext( BaseConfigurationRecord configRecord ) metodo di System.Configuration.ConfigurationElement sull'elemento.
  4. Chiamata internal void CallInit() metodo di System.Configuration.ConfigurationElement sull'elemento.
  5. Restituisce l'elemento preparato.

A proposito, se non ci saranno troppi elementi di raccolta diversi, considera l'utilizzo di qualcosa come:

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

In questo modo puoi evitare di trasmettere gli oggetti da MyCollection a tipo specifico.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top