我试图在IEnumerable上编写一个只适用于值类型和字符串的扩展方法。
public static string MyMethod<T>(this IEnumerable<T> source) where T : struct, string
然而&#39;字符串&#39;不是有效的约束,因为它是一个密封的类。
有没有办法做到这一点?
修改
我实际上要做的是为&#34; IN&#34;准备一个值列表。动态构造的SQL中的子句。
我有很多代码实例,例如以下我要清理的代码:
sb.AppendLine(string.Format("AND value IN ({0})", string.Join(",", Values.Select(x => x.ToSQL()).ToArray())));
ToSQL()具有处理SqlInjection的代码。
答案 0 :(得分:60)
也许你可以限制IConvertible类型?可以使用这些接口方法转换的所有系统原语也实现了接口,因此这种限制要求T为以下之一:
如果你有一个IConvertible,很可能它是这些类型之一,因为IConvertible接口很难实现,很少用于第三方类型。
主要缺点是,如果没有实际将T转换为这些类型之一的实例,那么您的所有方法都知道如何调用Object和IConvertible方法,或者采用Object或IConvertible的方法。如果你需要更多东西(比如使用+添加和/或连接的能力),我认为简单地设置两个方法,一个是结构类型的通用方法,另一个是字符串强类型,这将是最好的选择。 / p>
答案 1 :(得分:38)
您需要定义两个不同的方法:
public static string MyMethod<T>(this IEnumerable<T> source) where T : struct
public static string MyMethod(this IEnumerable<string> source)
答案 2 :(得分:28)
你为什么要这样做?也许还有另一种方法会更好。
答案 3 :(得分:14)
我使用了hack-solution:interface。 请参阅内置值类型和字符串类型已实现的接口:
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。
答案 4 :(得分:1)
使用类时,可以使用静态构造函数检查类型参数。
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.");
}
}
}