web-dev-qa-db-ja.com

ConfigurationElementCollectionおよびLinq

カスタム構成コレクション、要素などをいくつか作成しました。ここで、簡単なLinqステートメントを実行します。

ServerDetails servers = ConfigurationManager.GetSection("serverDetails") as ServerDetails;
var server = from s in servers
             where s.Name == serverName
             select s;

エラーが発生します:

ソースタイプ 'MyNamespace.ServerDetails'のクエリパターンの実装が見つかりませんでした。 「どこ」が見つかりません。

ServerElementには2つのプロパティがあります。

public class ServerElement : ConfigurationElement
{
    [ConfigurationProperty("ip")]
    public string IP
    {
        get { return (string)base["ip"]; }
        set { base["ip"] = value; }
    }

    [ConfigurationProperty("name", IsKey = true, IsRequired = true)]
    public string Name
    {
        get { return (string)base["name"]; }
        set { base["name"] = value; }
    }
}

ServerDetails

public sealed class ServerDetails : ConfigurationSection
{
    [ConfigurationProperty("ServerCollection")]
    [ConfigurationCollection(typeof(ServerCollection), AddItemName = "add")]
    public ServerCollection ServerCollection
    {
        get { return this["ServerCollection"] as ServerCollection; }
    }
}

ServerCollection

public sealed class ServerCollection : ConfigurationElementCollection
{
    public void Add(ServerElement ServerElement)
    {
        this.BaseAdd(ServerElement);
    }

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

    protected override ConfigurationElement CreateNewElement()
    {
        return new ServerElement();
    }

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

何か不足していますか? Linqをカスタム構成要素で使用できるように何かを追加する必要がありますか?

ちなみに、私はusing System.Linq;同じクラス内の他の場所で使用しているため、定義されています。

33
Neil Knight

わかりました。すべて型が弱いため、Cast<>またはOfType<>を明示的に呼び出すか、範囲変数に明示的な型を指定する必要があります。また、ServerCollectionServerDetailsプロパティを指定する必要があります。例えば:

ServerDetails servers = (ServerDetails) ConfigurationManager.GetSection("serverDetails");
var server = from ServerElement s in servers.ServerCollection
             where s.Name == serverName
             select s;
38
Jon Skeet

IEnumerable <T>実装で Brian Gideonの簡単な例 ofyield returnを使用して、ConfigurationElementCollectionを列挙できました。

次のようになります(元の質問を使用)。

public sealed class ServerCollection : ConfigurationElementCollection,
    IEnumerable<ServerElement>
{
    ...

    public new IEnumerator<ServerElement> GetEnumerator()
    {
        foreach (var key in this.BaseGetAllKeys())
        {
            yield return (ServerElement)BaseGet(key);
        }
    }
}

エラーが発生していない間:

ソースタイプ 'MyNamespace.ServerDetails'のクエリパターンの実装が見つかりませんでした。 「どこ」が見つからない

... LINQを使用してConfigurationElementCollectionを反復処理することもできませんでした。このソリューションで問題が解決され、LINQを使用してコレクションを反復処理できるようになりました。

17
cat5dev
 var server = ((ServerDetails) ConfigurationManager.GetSection("serverDetails")).
      ServerCollection.Cast<ServerElement>().FirstOrDefault(x => x.Name == serverName);
1
Jay Shah

非常に遅い答えですが、この拡張クラスを使用して、ConfigurationElementCollectionをIEnumerableに安全に変換します。

public static class ConfigurationElementCollectionExtension
{
    public static IEnumerable<T> ToEnumerable<T>(this ConfigurationElementCollection collection)
    {
        foreach (var element in collection)
        {
            if (element is T)
                yield return (T)element;

            yield return default;
        }
    }
}

以下の使用例

ConfigurationManager
   .GetSection("serverDetails"))
   .ServerCollection
   .ToEnumerable<ServerElement>()
   .FirstOrDefault(x => x.Name == serverName);
0
Xiaoguo Ge