値の型と文字列にのみ適用される拡張メソッドを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を処理するコードがあります。
いいえ、できません。ジェネリック制約は常に「AND」されます。つまり、意味がわかる場合(つまり、all制約を満たす必要があります)。
なぜこれをしたいのですか?おそらく、より適切に機能する別のアプローチがあります。
たぶん、IConvertible型に制限できますか?これらのインターフェイスメソッドを使用して変換できるすべてのシステムプリミティブもインターフェイスを実装するため、この制限ではTが次のいずれかである必要があります。
IConvertibleをお持ちの場合、これらのタイプの1つである可能性は非常に高く、IConvertibleインターフェイスは実装するのが非常に苦痛であり、サードパーティのタイプではめったに行われません。
主な欠点は、実際にTをこれらの型のインスタンスに変換せずに、ObjectメソッドとIConvertibleメソッド、またはObjectまたはIConvertibleを取得するメソッドを呼び出すだけでメソッドが実行できることです。さらに何かが必要な場合(+を使用して追加および/または連結する機能など)、2つのメソッドを設定するだけです.1つは構造体型に一般的なもの、もう1つは文字列に強く型付けされたものであることが、全体的な最善策です。
2つの個別のメソッドを定義する必要があります。
public static string MyMethod<T>(this IEnumerable<T> source) where T : struct
public static string MyMethod(this IEnumerable<string> source)
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を取得する場合があります。
クラスが使用されるときに、静的コンストラクターを使用して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.");
}
}
}