質問

タイプ別に多数の異なる CollectionElement を含む CollectionElementCollection を持つことは可能ですか。例:

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

このようなソリューションに必要なクラスはすべてあります。

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

しかし、アプリケーションを開始すると、次の予測可能なエラーが発生します。

認識できない属性「Type1SpecificProp」。

なぜなら Type1SpecificProp で定義されています MyType1 ない MyElement, 、特に次の場合 MyCollection 次のメソッドがあります:

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

つまりしたがって基本クラスを返します OnDeserializeUnrecognizedAttribute() in child クラスは決して呼び出されません。

そこで質問は次のとおりです。子クラスが未知の要素を自分で解決できるようにするにはどうすればよいですか?

役に立ちましたか?

解決 2

Microsoft.Practices.EnterpriseLibrary.Common.Configuration.PolymorphicConfigurationElementCollection<T> EntLib5 からは、この仕事をチャームとして実行します。

他のヒント

これについても調べてみました。 PolymorphicConfigurationElementCollection<T> 廃止されたようです。編集:そうではありません。以下の「abatishchev」のコメントを参照してください。私は古いバージョンをリンクしているだけです。

Rest Wing のソリューションは有望でしたが、残念なことに、別の名前空間に存在する内部メソッドを呼び出す必要がありました。これはリフレクションによって可能ですが、この場合、コーディングの美しさの代償を受け取ることはありません。

私もReflectionでソースを調べて、次の解決策を思いつきました。

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

CollectionType のオーバーライドは、上部の属性で指定されている場合でも必須です。オーバーライドされていない場合、基本クラスの CollectionType は引き続き「AddRemoveClearMap」を参照します。これは必須の「CreateNewElement(string elementName)」関数をトリガーしませんが、パラメーターのないバリアント「CreateNemElement()」です。同じ理由で、上書きされた IsElementName 関数は true を返す必要があります。

いくつかの共有属性を定義できる MyType1Config と MyType2Config の両方の基本クラスである ElementBaseConfig を作成したことに注意してください。

特定のタイプのインスタンス (MyType1 そして MyType2) は、子クラスが未知の要素または属性を独自に解決できるようにするために作成する必要があります。

以来、 CreateNewElement メソッドは要素の属性に関する情報を提供しません。つまり、特定の型のインスタンス化が行われる場所ではありません。

Reflector を使って少し調べてみると、次の部分的な呼び出しスタックにたどり着きます。

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

OnDeserializeUnrecognizedElement メソッドはオーバーライドできます MyCollection 特定の型のインスタンスを作成するためのクラス。パラメータなしのメソッドを使用する代わりに、 CallCreateNewElement メソッドを受信する新しいメソッドを使用してください XmlReader:

  1. 読み取り属性 type (その存在と有効性を確認してください)。
  2. 指定されたタイプの新しい要素を作成します。
  3. 電話 internal virtual void AssociateContext( BaseConfigurationRecord configRecord ) の方法 System.Configuration.ConfigurationElement 要素上で。
  4. 電話 internal void CallInit() の方法 System.Configuration.ConfigurationElement 要素上で。
  5. 準備された要素を返します。

ところで、異なるコレクション要素があまり多くない場合は、次のようなものを使用することを検討してください。

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

そうすれば、アイテムをキャストすることを避けることができます MyCollection 特定のタイプに。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top