メソッドの戻り値の型をジェネリックにする方法を教えてください。


166

このメソッドをジェネリックにして、文字列、ブール、整数、または倍精度浮動小数点数を返す方法はありますか?現在は文字列を返していますが、設定値として「true」または「false」が見つかった場合は、たとえばブール値を返したいと思います。

    public static string ConfigSetting(string settingName)
    {  
         return ConfigurationManager.AppSettings[settingName];
    }

各設定がどのタイプかを知る方法はありますか?
thecoshman 2012年

2
あなたが本当に聞きたい質問は、「アプリケーション構成を強く型付けするにはどうすればよいですか?」でも、それを使って適切な答えを書くのに時間がかかりすぎました。
Simon

ええ、理想的には、型をメソッドに渡す必要はありません。私が言及したのは4つのタイプだけです。したがって、「true」/「false」が設定されている場合、この関数がブール値を(メソッドに渡す必要なく)返すようにしたいので、おそらくintとdoubleを組み合わせて単なるdoubleにでき、それ以外はすべて文字列でなければなりません。すでに答えられていることはうまくいくでしょうが、私は毎回タイプを渡す必要があります、それはおそらくうまくいきます。
MacGyver 2012年

3
コメントは、設定名キーで取得された実際のデータに基づいて、実行時に厳密に型指定されたbool(または文字列、int、または何を持っているか)を返すメソッドを求めているように聞こえます。C#はこれを行いません。コンパイル時にその値のタイプを知る方法はありません。つまり、静的型付けではなく、動的型付けです。dynamicキーワードを使用すれば、C#がそれを実行できます。これにはパフォーマンスコストがかかりますが、構成ファイルを読み取る場合、パフォーマンスコストはほとんど問題になりません。
phoog 2012年

回答:


354

次のように、それをジェネリックメソッドにする必要があります。

public static T ConfigSetting<T>(string settingName)
{  
    return /* code to convert the setting to T... */
}

ただし、呼び出し元は期待するタイプを指定する必要があります。次にConvert.ChangeType、関連するすべてのタイプがサポートされていると想定して、を潜在的に使用できます。

public static T ConfigSetting<T>(string settingName)
{  
    object value = ConfigurationManager.AppSettings[settingName];
    return (T) Convert.ChangeType(value, typeof(T));
}

私はこれがすべて良い考えであると完全に確信しているわけではありません。


21
/ *設定をTに変換するコード... * /そして、これは小説全体に従います:)
Adrian Iftode

1
これには、取得したい設定のタイプを知る必要はありませんが、これは不可能かもしれません。
thecoshman 2012年

2
@thecoshman:そうですが、そうしなかった場合は、戻り値をどのように処理しますか?
George Duckett 2012年

5
この答えは、もちろん正しいのものであり、あなたが満足するOPの要求に注意して、それはおそらく別の方法(の古いアプローチすることを言及する価値だがConfigSettingStringConfigSettingBoolなど)は、短く明確に、より良い焦点になるメソッド本体の利点を持っています。
phoog

4
これが推奨されない場合、ジェネリック戻り値型の目的は何ですか?
bobbyalex 2013

29

あなたは使うことができますConvert.ChangeType()

public static T ConfigSetting<T>(string settingName)
{
    return (T)Convert.ChangeType(ConfigurationManager.AppSettings[settingName], typeof(T));
}

13

これを行うには多くの方法があります(OPの問題に固有の優先度順にリストされています)

  1. オプション1:ストレートなアプローチ-1つのジェネリック関数ではなく、期待するタイプごとに複数の関数を作成します。

    public static bool ConfigSettingInt(string settingName)
    {  
         return Convert.ToBoolean(ConfigurationManager.AppSettings[settingName]);
    }
    
  2. オプション2:ファンシーな変換方法を使用したくない場合 -値をオブジェクトにキャストしてからジェネリック型にキャストします。

    public static T ConfigSetting<T>(string settingName)
    {  
         return (T)(object)ConfigurationManager.AppSettings[settingName];
    }
    

    注-キャストが有効でない場合(あなたのケース)、エラーがスローされます。タイプキャストについてよくわからない場合は、これを行うことはお勧めしません。むしろ、オプション3に進んでください。

  3. オプション3:タイプセーフのジェネリック -型変換を処理するジェネリック関数を作成します。

    public static T ConvertValue<T,U>(U value) where U : IConvertible
    {
        return (T)Convert.ChangeType(value, typeof(T));
    } 
    

    -Tは予想されるタイプです。ここでwhere制約に注意してください(Uのタイプは、エラーから保護するためにIConvertibleである必要があります)


4
なぜ3番目のオプションをジェネリックにするのUですか?そのようにする意味はなく、メソッドを呼び出すのが難しくなります。IConvertible代わりに受け入れてください。質問の答えにならないので、この質問に2番目のオプションを含める価値はないと思います。また、おそらく最初のオプションでメソッドの名前を変更する必要があります...
Jon Skeet

7

メソッドの戻り値の型を、呼び出し中にメソッドに渡すGeneric型に変換する必要があります。

    public static T values<T>()
    {
        Random random = new Random();
        int number = random.Next(1, 4);
        return (T)Convert.ChangeType(number, typeof(T));
    }

そのメソッドを介して返す値には、型キャスト可能な型を渡す必要があります。

渡したジェネリック型に型キャストできない値を返す場合は、コードを変更するか、メソッドの戻り値にキャスト可能な型を渡す必要があります。したがって、このアプローチはお勧めしません。


スポット-私にとって最後の行return (T)Convert.ChangeType(number, typeof(T));は私が欠けていたものでした-乾杯
グレッグ・トレヴェリック

1

関数を作成し、総称型のputパラメータを渡します。

 public static T some_function<T>(T out_put_object /*declare as Output object*/)
    {
        return out_put_object;
    }

これは実際には、いくつかのユースケースではかなりスマートです。データベースからデータを引き出すようなものです。タイプTのデータのリストを取得することはわかっています。ロードメソッドは、どのタイプのTが今すぐ必要かを知りません。したがって、新しいList <WantedObject>をこれに渡すだけで、メソッドはそれを実行し、リストを返す前にリストを埋めることができます。いいね!
Marco Heumann

0

以下のコードを試してください:

public T? GetParsedOrDefaultValue<T>(string valueToParse) where T : struct, IComparable
{
 if(string.EmptyOrNull(valueToParse))return null;
  try
  {
     // return parsed value
     return (T) Convert.ChangeType(valueToParse, typeof(T));
  }
  catch(Exception)
  {
   //default as null value
   return null;
  }
 return null;
}

-1
 private static T[] prepareArray<T>(T[] arrayToCopy, T value)
    {
        Array.Copy(arrayToCopy, 1, arrayToCopy, 0, arrayToCopy.Length - 1);
        arrayToCopy[arrayToCopy.Length - 1] = value;
        return (T[])arrayToCopy;
    }

私はこれをコード全体で実行しており、それをメソッドに組み込む方法を望んでいました。これを共有したかったのは、戻り値にConvert.ChangeTypeを使用する必要がなかったためです。これはベストプラクティスではないかもしれませんが、私にとってはうまくいきました。このメソッドは、ジェネリック型の配列と配列の最後に追加する値を受け取ります。次に、最初の値を取り除いて配列がコピーされ、メソッドに取り込まれた値が配列の最後に追加されます。最後に、汎用配列を返します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.