10

CollectionElementsのタイプごとに異なる数の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()、子クラスで基本クラスを返すため、呼び出されることはありません。

したがって、問題は、子クラスが未知の要素を自分で解決できるようにする方法です。

4

3 に答える 3

11

これも調べました。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を作成したことに注意してください。このクラスで、いくつかの共有属性を定義できます。

于 2012-01-09T21:46:02.790 に答える
2

Microsoft.Practices.EnterpriseLibrary.Common.Configuration.PolymorphicConfigurationElementCollection<T>EntLib5からこの仕事を魅力としてやってください。

于 2011-12-21T08:26:02.887 に答える
1

子クラスが不明な要素または属性を自分で解決するには、特定のタイプ(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を特定のタイプにキャストすることを回避できます。

于 2011-02-20T00:59:29.663 に答える