24

私のプロジェクトの1つでは、次の2つの方法を使用しています。1.GetDoubleValueおよび2.GetIntValue。GetDoubleValueはdouble.TryParseを使用してstrstringをパラメーター化し、失敗した場合は0を返し、GetIntValueはint.TryParseをパラメーターstr stringに対して試行し、失敗した場合は0を返します。私が欲しいのは、これら2つのメソッドを1つのジェネリックメソッドに結合し、文字列strとともにパラメーターTも受け取るようにすることです。これにより、GetDoubleValueメソッドを使用する場合は、パラメーターTにdoubleを使用でき、GetIntValueメソッドを使用する場合は、パラメータTのInt

public double GetDoubleValue(string str)
{
    double d;
    double.TryParse(str, out d);
    return d;
}
public int GetIntValue(string str)
{
    int i;
    int.TryParse(str, out i);
    return i;
}

注:私はこのようなことを試しました。

private T GetDoubleOrIntValue<T>(string str) where T : struct 
{
    T t;
    t.TryParse(str, out t);
    return t;
}

編集

私のデータベースには、数値データ型を持つ異なるテーブルに30を超える列があります。ユーザーがテキストボックスに何も入力しない場合、つまり、テキストボックスのすべてまたは一部を空のままにした場合は、各列に0を挿入します。GetIntValueメソッドを使用しない場合、メソッド本体を30回以上使用する必要があります。それが私がメソッドアプローチを通じてこれを行っている理由です。たとえば、30以上の例のうち3つを書いています

cmd.Parameters.Add("@AddmissionFee", SqlDbType.Decimal).Value = GetIntValue(tbadmissionfee.Text);
cmd.Parameters.Add("@ComputerFee", SqlDbType.Decimal).Value = GetIntValue(tbcomputerfee.Text);
cmd.Parameters.Add("@NotesCharges", SqlDbType.Decimal).Value = GetDoubleValue(tbnotescharges.Text);

私は前述の2つの方法を組み合わせたいと思います。なぜなら、今日私はこのような2つの方法を持っているので、組み合わせてもプログラミングの改善は得られませんが、明日はこのような方法を数十個持って、1つの一般的な方法に組み合わせるほうがよいでしょう。たとえば、GetInt32Value、GetShortValueなどがあるかもしれません。これが必要な理由が明確になったことを願っていますか?

4

8 に答える 8

11

拡張メソッドまたは静的メソッドを作成することを検討します。

delegate bool TryParse<T>(string str, out T value);

public static T GetValue<T>(this string str, TryParse<T> parseFunc)
{
    T val;
    parseFunc(str, out val);
    return val;
}

次に、TryParse使用する実装を提供する必要があります。

int i = "1234".GetValue<int>(int.TryParse);

解析が失敗した場合、この関数はサイレントにデフォルト値を返すことに注意してください。デリゲートがfalseを返したdefault(T)場合は、戻ることをお勧めします。TryParse

于 2012-05-13T19:41:38.073 に答える
9

私はマーク・バイアーズに同意します。このメソッドをジェネリックにしようとするのはおそらく良い考えではありません。少しのコード重複は害を及ぼしません(それが本当にほんの少しである限り)。あなたがあなたのジェネリックバージョンでどれでも使うことができるという事実はstructまたそれを私には良い考えのように思わせません。

本当にこれを実行したい場合は、(Minustarが提案したように)リフレクションを使用してみることができますが、それは醜くて遅いでしょう。

代わりに、次を使用できますConvert.ChangeType()

private T GetValue<T>(string str) where T : struct 
{
    return (T)Convert.ChangeType(str, typeof(T));
}
于 2012-05-13T19:40:57.280 に答える
8

したがって、書く代わりに:

double d = GetDoubleValue(str);

これを書けるようになりたいですか?

double d = GetValue<double>(str);

動作させることができたとしても、どのようなメリットがありますか?個人的には、それがクライアントにとって大きな改善だとは思いません。唯一の利点は、同じメソッドを2回実装する必要がないことです。しかし、メソッドが単純であり、このタイプのコードの再利用を実装するのが難しいことを考えると、ここでは、これらの数行のコードを複製するのが妥当と思われます。

この問題はあなただけではありません。さまざまなタイプで機能する.NETFrameworkの他のメソッドを見て、それらがどのように解決したかを確認してください。BinaryReaderさまざまなタイプを読み取る方法は次のとおりです。

それはきれいではありませんが、それはそれが通常行われる方法です。


あなたのアップデートに関して、私はさらに2つのポイントがあります。

2つ以上のタイプがある可能性があり、これにより同じコードの重複が増える可能性があるとのことです。メソッドが非常に簡潔で単純であることを考えると、コードをコピーして貼り付けることは問題ではないようです。私の意見では、コードをコピーして貼り付けてはならないという規則の合理的な例外です。ここでのアプローチは重複の量を減らしますが、パブリックインターフェイスには同じような名前のメソッドがたくさん必要です。

ただし、リーがすでにコメントで述べているように、状況でデフォルト値を黙って使用するのは間違っているように思われることを言及することが重要だと思います。ユーザーがデータの入力を間違えた場合、エラーメッセージが表示されます。ある種の検証フレームワークを使用して、文字列が有効であることを確認し、文字列が無効な場合の問題をユーザーに通知する必要があります。すべてを検証したら、解析が成功することがわかっているので、int.Parse代わりに使用しても安全です。int.TryParseまた、解析が失敗した場合、それは例外的な状況(検証のバグ)であるため、アプリケーションが例外を除いてベイルアウトし、スタックトレースをログに記録するのは公平なようです。これは、バグを見つけて修正するのに役立ちます。

于 2012-05-13T19:31:40.233 に答える
8

あなたはこのようなことをすることができます:

   public static T GetDoubleOrIntValue<T>(this string str) where T : IConvertible
{
    var thisType = default(T);
    var typeCode = thisType.GetTypeCode();
    if (typeCode == TypeCode.Double)
    {
        double d;
        double.TryParse(str, out d);
        return (T)Convert.ChangeType(d,typeCode) ;
    }
    else if (typeCode == TypeCode.Int32)
    {
        int i;
        int.TryParse(str, out i);
        return (T)Convert.ChangeType(i, typeCode);
    }
    return thisType;
}

それからあなたがそれを呼ぶとき:

string d = "1.1";
string i = "3";

double doubleValue = d.GetDoubleOrIntValue<double>();
int intValue = i.GetDoubleOrIntValue<int>();

しかし、すべてが私にはちょっとばかげているように思えます。

編集:ジェネリックリターンタイプを提供するConvert.ChangeType...を使用して他の誰かを見ました。

于 2012-05-13T20:34:54.807 に答える
1

リフレクションを試すことができます。まず、<T>に置き換えられたタイプで「TryParse」メソッドを見つけてみてください。

T t;
var typeInfo = typeof(T);
var method = typeInfo.GetMethod("TryParse", BindingFlags.Public | BindingFlags.Static);
var result = (bool)method.Invoke(null, new object[] { str, t });

if (result)
    return t;

このコードはテストされていません。パフォーマンス的にも最適ではありません。

于 2012-05-13T19:31:19.483 に答える
1

簡単なサンプルを作成しました。コードは最適ではありませんが、期待どおりに機能します。

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(GetValue<int>("123"));
        Console.WriteLine(GetValue<double>("123.123"));
        Console.WriteLine(GetValue<DateTime>("2001-01-01 01:01:01"));
    }

    static T GetValue<T>(string s)
    {
        var tryParse = typeof (T).GetMethod(
            "TryParse", new [] {typeof(string), typeof(T).MakeByRefType()});
        if (tryParse == null)
            throw new InvalidOperationException();


        T t = default (T);
        var parameters = new object[] {s, t};
        var success = tryParse.Invoke(null, parameters);
        if ((bool) success) t = (T)parameters[1];
        return t;
    }
}
于 2012-05-13T19:39:57.873 に答える
0

ご覧のとおり、またはに制限where Tすることはできません。そのため、おそらくその場所にいます(intとdoubleは構造体ではありません)。値型は、ジェネリックスの制限として使用できません。DoubleInt32struct

TryParseしたがって、メソッドが存在することを確認して安全に入力することはできません。@ieによる回答のように、Tをタイプチェックして、doubleまたはintのいずれかである場合は、例外をスローする必要があります。

私の提案は、異なる署名を使用することです。

private static bool GetValue(string str, out double result)
{
...    
}

private static bool GetValue(string str, out int result)
{
...    
}

または、インターフェースを導入することもできますIParsable。ボックスdoubleまたはint結果をその中に入れ、doubleまたはintegerへの暗黙の変換を実装します。

于 2012-05-13T19:40:41.937 に答える
0

拡張メソッドはどうですか?

public static class Extensions
{    
    public static Nullable<T> TryParse<T>(this String str) where T:struct
    {
        try
        {
            T parsedValue = (T)Convert.ChangeType(str, typeof(T));
            return parsedValue;
        }
        catch { return null; }
    }
}

利用方法 :

int i = "123".TryParse<int>() ?? 0;
于 2016-05-05T12:20:16.343 に答える