2010-12-15 12 views
2

私は、本質的にはパーサージェネレータでなければならないことに対する簡単な概念証明を書いています。ジェネリック型に基づいた関数を返すことはできますか?

基本的には、指定された型のオブジェクトに文字列を変換する関数を返す関数を書く方法を探しています。つまり、以下のことを本質的に行うことができます:

Func<string, double> ConvertToDouble = BuildConverter(typeof(0.0)); 

明らかにこれはかなり工夫された例ですが、私が単純なバージョンを行うことができれば、より複雑なバージョンを行うことができます!

FWIW、私が最終的にしようとしているのは、クラスに値の文字列をマップすることですが、できるだけ柔軟にするために、関数を返す関数を用意します変換。機能面では、私はこのようなものしたいと思う:すべてで動作しますが、それはありません

public static Func<string, T> BuildParser<T>(T t) 
    { 
     if (t is String) 
     return new Func<string, T>(x => x.ToString()); 
     if (t is double) 
     return new Func<string, T>(x => double.Parse(x)); 
    } 

:最初の試みとして、

a -> (string -> a) 

を、私はこれをやってみましたどのようなアプローチを取っているのか、私はちょっと気になってしまいました。だから、どんな助けでも大いに感謝されます!

+3

あなたは、あなたの一般的な機能で_types_を探している場合、ジェネリックのポイントを逃しているように見えます。 – Oded

+2

実行時の決定が必要な場合は、ジェネリックを使用しないでください。コンパイル時の決定が必要な場合は、 "is"を使用しないでください。 –

+0

@Oded - 私が同意するかどうかはわかりませんが、特定の型の多型を探しています。 – MrBear

答えて

0

あなたはstructタイプでclassを混在させることはできません。それを超えて、それは動作します。

private void Testing() { 
    var func = BuildParserStruct<double>(); 
    double value = func("5"); 
} 

public static Func<string, T> BuildParserClass<T>() where T : class 
{ 
    return x => x as T; 
} 

public static Func<string, T> BuildParserStruct<T>() where T : struct 
{ 
    return (x => (T)Convert.ChangeType(x, typeof(double))); 
} 
+0

これは面白そうですね!私はそれを試してみましょう - 私は完全に 'どこT:'の構文について忘れてしまいます。 – MrBear

+0

'' class'と 'struct'型を混ぜることができないと思いますか?これは単一の 'BuildParser 'メソッドで行うことができます。不要な場合は 'BuildParserClass 'と 'BuildParserStruct 'メソッドを別々にする必要はありません。 (例については私の答えを参照してください。) – LukeH

+0

十分に公正です。私が言っておくべきことは、ジェネリックメソッドは、リフレクションを使わずに構造体とクラスの型(または派生型)の両方をインスタンス化できないということです。この制限はあなたのソリューションには影響しません。ジェネリックメソッドは何もインスタンス化しないからです。私はあなたのソリューションが賢明であると判断しましたが、制限があっても30種類のキャッシュを必要とします。 )... – rsenna

0

私は、コンパイル時に特定の動作を検証したいと思っています。単にConvertと呼ぶのではなく、使用する個々のメソッドを書くのはなぜですか?あなたのif文が達成するのは、適切な変換方法を選択しなければならないプログラマーの役割を果たすことだけです。

実行時に動作を選択したい場合は、Func<string, object>を返し、メソッドを非汎用的にする必要があります。

メソッドで一般的なタイプTを使用する際の問題は、メソッドへの呼び出しごとにTが固定され、メソッド内のロジックがTを1回の呼び出しで変化させると仮定します(Tは文字列、別の場合にはTは小数である)。コンパイラはこれをソートすることはできません。リターン可能なインスタンスの両方を同じ型にする必要があります。

+0

私の例が現れている限り、あなたは正しいです - それは概念の証明です。最終的には、メッセージをカンマ区切りの文字列として送信するメッセージングシステムがあり、各メッセージはクラス(または構造体)にマップできます。これは、メッセージシステムを使用するアプリケーションをここに書くたびに、クラスにマップする方法をコードに渡す必要があることを意味します。私がやりたいことは、本質的に、マッパージェネレータをそのまま書いて自動化することです。 – MrBear

0

私はあなたがしようとしていることは確かではありませんが、このような助けになるでしょうか?

var stringParser = GetParser<string>(); 
string s = stringParser("test"); 

var doubleParser = GetParser<double>(); 
double d = doubleParser("42"); 

// ... 

public static Func<string, T> GetParser<T>() 
{ 
    return (Func<string, T>)_parserCache[typeof(T)]; 
} 

private static readonly Dictionary<Type, Delegate> _parserCache = 
    new Dictionary<Type, Delegate> 
     { 
      { typeof(string), new Func<string, string>(x => x) }, 
      { typeof(double), new Func<string, double>(x => double.Parse(x)) } 
      // etc 
     }; 
0

ADO.Netは、オブジェクトを返すので、いつも私を気に実行スカラ機能を持っています

は、以下のコードを参照してください。適切な型を返す汎用のラッパー関数を書くことができます。もちろん、これは返される型が分かっていることを前提としています。

やや簡略化:

public T ExecuteScalar<T>() 
    { 
     return (T)Command.ExecuteScalar(); 
    } 
関連する問題