4

と の 2 つのデータ構造がDictionary<string, string>ありMultimap<string, string>ます。Multimap は、実際にはボンネットの下にある単なる辞書です。この質問からコードを取得しました。クラス定義は次のとおりです。

public class Multimap<TKey, TValue> : Dictionary<TKey, HashSet<TValue>>
{ ... }

どちらのデータ構造にも.Add(TKey key, TValue value)メソッドがあります。

特定のファイルからこれらのマップを作成するクラスがあります。現在、次の2つの方法があります。

    public Dictionary<string, string> PopulateDictionary(...)
    {
        Dictionary<string, string> returnDictionary = new Dictionary<string, string>();
        ...
        foreach (...)
        {
            ...
            returnDictionary.Add(key, value);
        }
        return returnDictionary;
    }

    public Multimap<string, string> PopulateMultimap(...)
    {
        Multimap<string, string> returnMultimap = new Multimap<string, string>();
        ...
        foreach (...)
        {
            ...
            returnMultimap.Add(key, value);
        }
        return returnMultimap;
    }

ご覧のとおり、どちらも約 25 行の長さでまったく同じであり、唯一の違いは戻り値の型です。私がやろうとしているのは、これを1つの方法に凝縮することです。私の最初の試みは、メソッドを持つことでした

public Dictionary<string, object> PopulateGenericDictionary(...)
{ ... }

objectまたはのどちらstringかでしHashSet<string>た。Dictionary<string, object>しかし、 からにキャストするのはあまり運がありませんでしたMultimap<string, string>

メソッドからロジックを抽出することはオプションですが、それは素晴らしいことではありません。foreach ループのため、2 つのメソッド内には常に何らかのロジックが存在します。最終的にメソッドは 2 倍小さくなりますが、それでも 2 つの同一のメソッドが存在するため、問題を真に解決することはできません。

これは私の理想的なメソッド構造です。

public Dictionary<string, string> PopulateDictionary(...)
{
    return MethodThatDoesAllTheLogic(...);
}
public Multimap<string, string> PopulateMultimap(...)
{
    return MethodThatDoesAllTheLogic(...);
}
public ??? MethodThatDoesAllTheLogic(...)
{ ... }

私はキャストとジェネリックをいじっていますが、うまくいきません。何か案は?

編集

ミリムースのソリューションを使用しました。ここに私のコードがあります:

    public Dictionary<string, string> GenerateDictionary(...)
    {
        Dictionary<string, string> returnMap = new Dictionary<string, string>();
        PopulateDictionary(returnMap.Add, ...);
        return returnMap;
    }

    public Multimap<string, string> GenerateMultimap(...)
    {
        Multimap<string, string> returnMap = new Multimap<string, string>();
        PopulateDictionary(returnMap.Add, ...);
        return returnMap;
    }

    private static void PopulateGenericDictionary(Action<string, string> addFunc, ...)
    {
        ...
        foreach (...)
        {
            addFunc(key, value);
        }
    }

もっときれいに!

4

6 に答える 6

8

共通のインターフェイスがないことを回避するには、一連のデリゲート型パラメーターを使用して 1 つのアドホックを作成できます。

void MethodThatDoesAllTheLogic(Action<string, string> addFunc)
{
    // ...
    addFunc(key, value);
    // ...
}

public Dictionary<...> PopulateDictionary()
{
    // ...
    MethodThatDoesAllTheLogic(result.Add);
}

(必要に応じてパラメータを追加します。)

于 2013-02-19T18:19:34.133 に答える
3

ヘルパー メソッドで実際のコレクションを作成することはまったく避けたいと思います。既存のコレクションにデータを入力するだけです。Addメソッドはどちらの場合も同じシグネチャを持っているため、これははるかに効果的に実行できます。Addデリゲートを使用してメソッドを受け入れることができます。

public static void PopulateMapping<TKey, TValue>(Action<TKey, TValue> addMethod,
    IEnumerable<TKey> data) //include other parameters needed to populate the data
{
    foreach (var key in data)
    {
        addMethod(key, default(TValue));
    }
}

次に、次のように使用されます。

public static Dictionary<string, string> PopulateDictionary()
{
    Dictionary<string, string> output = new Dictionary<string, string>();
    PopulateMapping<string, string>(output.Add, new string[] { "a" });
    return output;
}
于 2013-02-19T18:26:47.007 に答える
0

このアプローチが役立つかどうかを確認します。重要なのは、オブジェクト(ディクショナリまたはマルチマップ)の作成と値の取得を抽象化することです。これは、設定方法の2つの違いです。

public  Dictionary<string, TValue> Populate<TValue>( Dictionary<string, TValue> returnDict, Func<SomeType, TValue> valueProvider)
{
    string key = null;
    ...
    foreach (...)
    {
        ...
        returnDict.Add(key, valueProvider(value));
    }
    return returnDict;
}

呼び出しの例は次のとおりです。

public void Test()
{
    Populate(new Multimap<string, HashSet<string>>(), (t) => new HashSet<HashSet<string>>());
}

valueProviderデリゲートが問題に適しているかどうかはわかりません。それについてもっと情報を与えるようにしてください。

于 2013-02-19T18:40:47.187 に答える
0

Add メソッドのみを探している場合は、両方のオブジェクトが を共有する必要がありますIDictionary。ただし、そのAddメソッドはオブジェクトのみを使用します。これはおそらく、メソッドでジェネリックを使用せずに取得できる最も近いものです...しかし、その時点でジェネリックの利点が失われます。

于 2013-02-19T18:21:34.417 に答える
-1

ジェネリックスを使用するC#では、Dictionaryの場合、特定のクラスを拡張または実装するように要求できます。これを実現する方法は次のとおりです。

public T Populate<T>(string val) where T : Dictionary<string, string>, new()
        {
            T returnDict = new T();
            returnDict.Add("key", "val");
            return returnDict;
        }
于 2013-02-19T18:23:44.227 に答える
-1

TValue の型を除いて内部ロジックが完全に同一である場合、つまり単語ごとに同一である場合は、次のようにすることができます。

IDictionary<string, TValue> MethodThatDoesAllTheLogic<TValue>(whatever)
{
  // word for word-identical logic
}

メソッドが TValue を唯一の型パラメーターとして取るようにしました。これが唯一の違いです (あなたが示した例で): どちらのメソッドも最初の型パラメーターとして文字列を持っています。

ETA: これは、MultiMap が を実装していることを前提としていますIDictionary<K,V>。から継承したとおっしゃっていたので、継承しているDictionary<K,V>と思いました。

于 2013-02-19T18:19:39.690 に答える