9

オブジェクトレベルで適用する拡張メソッドを作成する必要があるのか​​、それともクラス階層の下位に配置する必要があるのか​​疑問に思っています。私が言いたいのは、次のようなものです。

public static string SafeToString(this Object o) {
    if (o == null || o is System.DBNull)
        return "";
    else {
        if (o is string)
            return (string)o;
        else
            return "";
    }
}

public static int SafeToInt(this Object o) {
    if (o == null || o is System.DBNull)
        return 0;
    else {
        if (o.IsNumeric())
            return Convert.ToInt32(o);
        else
            return 0;
    }
}
//same for double.. etc

基になるデータベースは残念ながらnullの可能性がある列を非常に自由に使用できるため、nullになる可能性のあるデータベースデータ(OleDbDataReaderから)を大量に処理する必要があるため、これらのメソッドを作成しました。そして、私の生活を少し楽にするために、私はそれらの拡張メソッドを思いつきました。

私が知りたいのは、これが良いスタイルなのか、許容できるスタイルなのか、悪いスタイルなのかということです。Objectクラスを「汚染」するので、少し心配です。

よろしくお願いします:)

キリスト教徒

PS私はそれを意図的に「主観的」としてタグ付けしませんでした。

4

7 に答える 7

7

いいえ、それは良い習慣ではありません。可能な限り低いポイントで拡張メソッドを適用する必要があります。(ほとんど)すべてのための時間と場所があると思いますが、拡張メソッドSystem.Objectはほとんど適切ではありません。このような拡張メソッドを継承スタックのはるか下に適用できるはずです。そうしないと、インテリセンスが乱雑になり、他の開発者によって誤って使用/依存されることになります。

ただし、Null値を処理するためのデータオブジェクトの拡張メソッドは、拡張メソッドの非常に優れた使用法です。それらをOleDbDataReaderに正しく配置することを検討してください。ValueOrDefaultという一般的な拡張メソッドがあります。。。さて、私はあなたにそれを見せます:

<Extension()> _
Public Function ValueOrDefault(Of T)(ByVal r As DataRow, ByVal fieldName As String) As T
    If r.IsNull(fieldName) Then
        If GetType(T) Is GetType(String) Then
            Return CType(CType("", Object), T)
        Else
            Return Nothing
        End If
    Else
        Return CType(r.Item(fieldName), T)
    End If
End Function

それはVBですが、あなたは絵を手に入れます。この吸盤は私に多くの時間を節約し、データ行から読み取るときに本当にきれいなコードを作ります。 あなたは正しい方向に進んでいますが、あなたの呪文の感覚は正しいです:あなたは拡張メソッドが高すぎます。

拡張メソッドを別の名前空間に配置することは、何もないよりはましです(これは、名前空間の完全に有効な使用法です。Linqはこれを使用します)が、そうする必要はありません。これらのメソッドをさまざまなdbオブジェクトに適用するには、拡張メソッドをIDataRecordに適用します。

于 2010-03-10T14:18:07.897 に答える
5

フレームワーク設計ガイドラインは、これを行わないようにアドバイスしています。ただし、これらのガイドラインは特にフレームワーク向けであるため、(基幹業務の)ビジネスアプリケーションで非常に役立つ場合は、そうしてください。

ただし、これらの拡張メソッドをオブジェクトに追加すると、IntelliSenseが混乱し、他の開発者を混乱させる可能性があることに注意してください。彼らはそれらの方法を見ることを期待しないかもしれません。この場合、昔ながらの静的メソッドを使用してください:-)


私のCPU(私の脳)が可能なものを見つけるように訓練されていることで、私が個人的にどこにでも拡張メソッドを散りばめることについて厄介だと思うことNullReferenceExceptionの1つ。拡張メソッドはインスタンスメソッドのように見えるため、そのようなコードを読み取るときに、私の脳はソースコードパーサーPossibleUseOfNullObjectによる割り込みを受け取ることがよくあります。その場合、私は実際に発生する可能性があるかどうかを分析する必要があります。これにより、中断が頻繁に発生するため、コードの読み取りがはるかに困難になります。NullReferenceException

このため、拡張メソッドの使用については非常に保守的です。しかし、これは私がそれらが有用であるとは思わないという意味ではありません。地獄!拡張メソッドを広範囲に使用する前提条件検証用のライブラリも作成しました。そのライブラリを書き始めたとき、私は最初に拡張メソッドを定義しました。System.Objectただし、これは再利用可能なライブラリであり、VB開発者によって使用されるため、これらの拡張メソッドをで削除することにしましたSystem.Object

于 2010-03-10T14:20:11.667 に答える
5

「フレームワーク設計ガイドライン」からの抜粋

どうしても必要な場合を除いて、System.Objectで拡張メソッドを定義することは避けてください。その際、VBユーザーはこのように定義された拡張メソッドを使用できず、そのため、拡張メソッドに伴うユーザビリティ/構文上の利点を利用できないことに注意してください。

これは、VBでは、変数をオブジェクトとして宣言すると、その変数に対するすべてのメソッド呼び出しがレイトバインドされるのに対し、拡張メソッドへのバインドはコンパイル時に決定される(アーリーバインドされる)ためです。例えば:

public static class SomeExtensions{
     static void Foo(this object o){…} } … Object o = … o.Foo(); 

この例では、Fooの呼び出しはVBで失敗します。代わりに、VB構文は次のようになります。SomeExtensions.Foo(o)
ガイドラインは、同じバインディング動作が存在する、または拡張メソッドがサポートされていない他の言語に適用されることに注意してください。

于 2010-03-10T14:22:04.090 に答える
4

System.Objectの拡張メソッドの汚染は、一般的なケースでは非常に煩わしい場合がありますが、これらの拡張メソッドを別の名前空間に配置して、開発者がこれらのメソッドの使用を積極的に選択する必要があるようにすることができます。

これを単一責任の原則に従うコードと組み合わせると、この名前空間を比較的少数のクラスにインポートするだけで済みます。

このような状況では、このような拡張方法が受け入れられる場合があります。

于 2010-03-10T14:21:06.947 に答える
2

おそらく、拡張メソッドをIDataRecordインターフェイスに追加することを検討しますか?(OleDbDataReaderが実装します)

public static class DataRecordExtensions
{
    public static string GetStringSafely(this IDataRecord record, int index)
    {
        if (record.IsDBNull(index))
            return string.Empty;

         return record.GetString(index);            
    }

    public static Guid GetGuidSafely(this IDataRecord record, int index)
    {
        if (record.IsDBNull(index))
            return default(Guid);

        return record.GetGuid(index);
    }

    public static DateTime GetDateTimeSafely(this IDataRecord record, int index)
    {
        if (record.IsDBNull(index))
            return default(DateTime);

        return record.GetDateTime(index);
    }
}
于 2010-03-10T14:23:25.990 に答える
0

System.Objectすでに述べた理由に加えて、 VBでは拡張メソッドがサポートされていないことに注意してください(変数が静的に型付けされSystem.Objectている場合、および変数が静的に型付けされていない場合は、Object別のより具体的な型を拡張する必要があります) )。

この制限の理由は、下位互換性です。詳細については、この質問を参照してください。

于 2010-03-10T14:25:17.257 に答える
0

ベストプラクティスではないことはわかっていますが、私のプロジェクトでは、データ型を変換するためにこの拡張機能を含めるのが好きで、Convertクラスよりもはるかに簡単です。

public static T ChangeType<T>(this object obj) where T : new()
{
    try
    {
        Type type = typeof(T);
        return (T)Convert.ChangeType(obj, type);
    }
    catch
    {
        return new T();
    }
}

すべてのオブジェクトに表示されますが、通常、拡張機能のリストを作成する代わりに、これを使用します。

このように動作します...

int i = "32".ChangeType<int>();
bool success = "true".ChangeType<bool>();
于 2010-03-31T17:37:15.850 に答える