web-dev-qa-db-ja.com

値型と文字列を含むC#の一般的な制約

値の型と文字列にのみ適用される拡張メソッドをIEnumerableで作成しようとしています。

public static string MyMethod<T>(this IEnumerable<T> source) where T : struct, string

ただし、 'string'はシールクラスであるため、有効な制約ではありません。

これを行う方法はありますか?

編集:

私が実際にやろうとしているのは、動的に構築されたSQLの「IN」句の値のリストを準備することです。

クリーンアップしたい次のようなコードのインスタンスがたくさんあります。

sb.AppendLine(string.Format("AND value IN ({0})", string.Join(",", Values.Select(x => x.ToSQL()).ToArray())));

ToSQL()には、SqlInjectionを処理するコードがあります。

41
Brett Postin

いいえ、できません。ジェネリック制約は常に「AND」されます。つまり、意味がわかる場合(つまり、all制約を満たす必要があります)。

なぜこれをしたいのですか?おそらく、より適切に機能する別のアプローチがあります。

28
Jon Skeet

たぶん、IConvertible型に制限できますか?これらのインターフェイスメソッドを使用して変換できるすべてのシステムプリミティブもインターフェイスを実装するため、この制限ではTが次のいずれかである必要があります。

  • ブール値
  • バイト
  • チャー
  • 日付時刻
  • 小数
  • ダブル
  • Int(16、32、および64ビット)
  • SByte
  • シングル(フロート)
  • ストリング
  • UInt(16、32、および64ビット)

IConvertibleをお持ちの場合、これらのタイプの1つである可能性は非常に高く、IConvertibleインターフェイスは実装するのが非常に苦痛であり、サードパーティのタイプではめったに行われません。

主な欠点は、実際にTをこれらの型のインスタンスに変換せずに、ObjectメソッドとIConvertibleメソッド、またはObjectまたはIConvertibleを取得するメソッドを呼び出すだけでメソッドが実行できることです。さらに何かが必要な場合(+を使用して追加および/または連結する機能など)、2つのメソッドを設定するだけです.1つは構造体型に一般的なもの、もう1つは文字列に強く型付けされたものであることが、全体的な最善策です。

63
KeithS

2つの個別のメソッドを定義する必要があります。

public static string MyMethod<T>(this IEnumerable<T> source) where T : struct
public static string MyMethod(this IEnumerable<string> source)
38
Steven

Hack-solution:インターフェイスを使用しました。組み込みの値型と文字列型が実装しているインターフェースをご覧ください。

_struct Int32 : IComparable, IFormattable, IConvertible, IComparable<int>, IEquatable<int>

class String : IComparable, ICloneable, IConvertible, IComparable<string>, IEnumerable<char>, IEnumerable, IEquatable<string>

struct Boolean : IComparable, IConvertible, IComparable<bool>, IEquatable<bool>

struct DateTime : IComparable, IFormattable, IConvertible, ISerializable, IComparable<DateTime>, IEquatable<DateTime>

struct UInt64 : IComparable, IFormattable, IConvertible, IComparable<ulong>, IEquatable<ulong>

struct Single : IComparable, IFormattable, IConvertible, IComparable<float>, IEquatable<float>

struct Byte : IComparable, IFormattable, IConvertible, IComparable<byte>, IEquatable<byte>

struct Char : IComparable, IConvertible, IComparable<char>, IEquatable<char>

struct Decimal : IFormattable, IComparable, IConvertible, IComparable<decimal>, IEquatable<decimal>
_

_IComparable,IConvertible,IEquatable<T>__制約を使用できます。このような:

_ public static void SetValue<T>(T value) where T : IComparable, IConvertible, IEquatable<T>
    {
        //TODO:
    }
_

または、型コードを使用して、制約なしでデータ時間を確認できます。

_public static void SetValue<T>(T value)
    {
        switch (Type.GetTypeCode(typeof(T)))
        {
            #region These types are not what u want, comment them to throw ArgumentOutOfRangeException

            case TypeCode.Empty:
                break;
            case TypeCode.Object:
                break;
            case TypeCode.DBNull:

                #endregion

                break;
            case TypeCode.Boolean:
                break;
            case TypeCode.Char:
                break;
            case TypeCode.SByte:
                break;
            case TypeCode.Byte:
                break;
            case TypeCode.Int16:
                break;
            case TypeCode.UInt16:
                break;
            case TypeCode.Int32:
                break;
            case TypeCode.UInt32:
                break;
            case TypeCode.Int64:
                break;
            case TypeCode.UInt64:
                break;
            case TypeCode.Single:
                break;
            case TypeCode.Double:
                break;
            case TypeCode.Decimal:
                break;
            case TypeCode.DateTime:
                break;
            case TypeCode.String:
                break;
            default:
                throw new ArgumentOutOfRangeException();
        }
    }
_

パラメータタイプにはオブジェクトタイプではなくジェネリックタイプを使用することに注意してください。そうしないと、値がnullのときにコードラインType.GetTypeCode(value.GetType())でNULL EXCEPTIONを取得する場合があります。

15
Sean C.

クラスが使用されるときに、静的コンストラクターを使用してtypeパラメーターを確認できます。

class Gen<T> {
    static Gen() {
        if (!typeof(T).IsValueType && typeof(T) != typeof(String))
        {
            throw new ArgumentException("T must be a value type or System.String.");
        }
    }
}
2
Tereza Tomcova