2011-08-30 19 views
2

この質問の末尾に記載されているクラスを「一般化」できる人はいますか?クラスを "GetStateDelegate"型の代理人にロックしないようにしたいですが、一般的な代理人です。それは可能ですか?このクラスを一般的なクラスにすることはできますか?

私は物事のカップルを試してみたが、1)C#は、この種のクラス宣言を好きではない:

public class StringToMethodMapper<T> where T: System.Delegate 

これは

「型パラメータ制約としてSystem.Delegateを使用することはできません」得

正しい軌道に乗るためのヒントがありがたいです。また、ソリューションが存在する場合、私は消費者ができるだけ変更の影響を受けないようにしたい。たとえば、 "Add(string、delegate)"の呼び出しコードを変更しないでください。

コード:これを行うには

public delegate bool GetStateDelegate(object someObject); 

public class StringToMethodMapper 
{ 
    private Dictionary<string, GetStateDelegate> _methods; 

    public StringToMethodMapper() 
    { 
     _methods = new Dictionary<string, GetStateDelegate>(); 
    } 

    public void Add(string key, GetStateDelegate method) 
    { 
     _methods.Add(key, method); 
    } 

    internal virtual GetStateDelegate GetMethodFor(string key) 
    { 
     foreach (var storedKey in _methods.Keys) 
     { 
      if (key.ToUpper().StartsWith(storedKey.ToUpper())) 
      { 
       return _methods[storedKey]; 
      } 
     } 
     return null; 
    } 
} 

答えて

1

一般的に言うと...まあ、それは可能です。私はUnconstrained Melodyというライブラリを持っています。このライブラリはジェネリックのためにILのリライティングをデリゲートの制約で使用しています。そして、あなたのコードに同じILリライタを使用することができます。しかし、それはかなり醜いです。基本的に、ILは必要な制約をサポートしていますが、C#では必要ありません。 「MulticastDelegateから派生し、MulticastDelegateを含まないタイプでなければならない」という制限はありません。だからだれかStringToMethodMapper<MulticastDelegate>を作成することはできますが、それはかなり難しいことです。

代理人の署名(たとえば「常に3つのパラメータと無効な返品」)が付いていれば、Georgeさんの回答のアプローチを使用できます。 の代理人タイプがの場合は、ILの書き換えアプローチに拘束されているか、制約を破棄しています。


(コメントに基づいて編集された。)

コードの残りの部分の面では、それは辞書の非常に遅い使用です。現在、O(n)ルックアップがあります。 経由で通常のDictionaryアクセスを使用しますが、コンストラクタにStringComparer.OrdinalIgnoreCase(または類似のもの)を渡して、大文字と小文字を区別しない一致を取得してください。それは間違いなく始まりの試合をしないだろう...あなたの現在のアプローチは決して確定的ではありません。 "foo"と "fo"を辞書のキーとして使い分けることができます。どちらも一致しますので、イテレータがキーを返す順序に頼っています。いい考えではありません。

あなたが本当にStartsWith動作が必要な場合は、trie実装調査したいかもしれません - あるいはあなたがO(N)のルックアップに満足しているならば、私はそれを明確にあなたが本当に使用していないことを確認するためにList<KeyValuePair<string, TDelegate>>を続けるだろうそれは辞書として。

+0

TrygetValueを使うことができないので、StartsWithの相変わらずのことがポイントです。私の元のコードでは、例外をスローする重複したマッチのチェックがありますが、質問のためにはそれが重要です。私はあなたの図書館を見ていきます - 面白そうです! – Nilzor

+0

...と私はあなたが代理人の_any_種類を持つことはできないと言って私の質問に答えると思います。 – Nilzor

+0

@Nilzor:まあ、ILのリライティング手法でのみ。 –

0

一つの方法は、

public interface IGetState 
{ 
    bool GetState(object someObject); 
} 

は、あなたがあなたの制約として、このインタフェースを使用することができますインターフェイスのためのデリゲートを交換することです

public class StringToMethodMapper<T> where T: IGetState 
{ 
    ... 
} 

次に、特定のものを作成するためのインターフェイスを実装することができます。たとえば、

public class FileSystemState : IGetState 
{ 
    public bool GetState(object someObject) 
    { 
     // get state from the FS 
    } 
} 

、その後

var fileSystemMapper = new StringToMethodMapper<FileSystemState>(); 
+0

これは機能しますが、呼び出しコードを変更する必要があります。 – Nilzor

1

何か以下のように、おそらく(IDEなしで入力されました)。明らかに、クライアントは汎用パラメータを追加する必要がありますが、私はまだ追加するための呼び出しが動作すると思います。

public class StringToMethodMapper<T, TResult> 
{ 
    private Dictionary<string, Func<T, TResult>> _methods; 

    public StringToMethodMapper() 
    { 
     _methods = new Dictionary<string, Func<T, TResult>>(); 
    } 

    public void Add(string key, Func<T, TResult> method) 
    { 
     _methods.Add(key, method); 
    } 

    internal virtual Func<T, TResult> GetMethodFor(string key) 
    { 
     foreach (var storedKey in _methods.Keys) 
     { 
      if (key.ToUpper().StartsWith(storedKey.ToUpper())) 
      { 
       return _methods[storedKey]; 
      } 
     } 
     return null; 
    } 
} 
+0

これはC#で可能なことを考えてみたいと思っているものに最も近いものだと思います。ありがとう。 – Nilzor

関連する問題