C#包含值类型和字符串的通用约束

Bre*_*tin 44 c# string generics constraints value-type

我正在尝试在IEnumerable上编写一个扩展方法,它只适用于值类型和字符串.

public static string MyMethod<T>(this IEnumerable<T> source) where T : struct, string
Run Code Online (Sandbox Code Playgroud)

但是'string'不是有效的约束,因为它是一个密封的类.

有没有办法做到这一点?

编辑:

我实际上要做的是为动态构造的SQL中的"IN"子句准备一个值列表.

我有很多代码实例,例如以下我要清理的代码:

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

ToSQL()具有处理SqlInjection的代码.

Kei*_*thS 67

也许你可以限制IConvertible类型?可以使用这些接口方法转换的所有系统原语也实现了接口,因此这种限制要求T为以下之一:

  • 布尔
  • 字节
  • 烧焦
  • 约会时间
  • 十进制
  • Int(16,32和64位)
  • 为SByte
  • 单(浮)
  • UInt(16,32和64位)

如果你有一个IConvertible,很可能它是这些类型中的一种,因为IConvertible接口很难实现,很少为第三方类型做.

主要的缺点是,如果没有实际将T转换为这些类型之一的实例,您的所有方法都将知道如何调用Object和IConvertible方法,或者采用Object或IConvertible的方法.如果你需要更多的东西(比如使用+添加和/或连接的能力),我认为简单地设置两个方法,一个是结构类型的通用方法,另一个是强类型的字符串,这将是最好的选择.

  • 很好的主意!我没有想到这一点. (2认同)

Ste*_*ven 39

您需要定义2个单独的方法:

public static string MyMethod<T>(this IEnumerable<T> source) where T : struct
public static string MyMethod(this IEnumerable<string> source)
Run Code Online (Sandbox Code Playgroud)

  • 您还可以拥有第三个私有方法,这两个方法都调用该方法以使事情变得更加干燥。请参阅类似问题的[此答案](http://stackoverflow.com/a/4109547/957950)。 (4认同)
  • 虽然“你不能”的答案更正确,但这个答案更有用。 (3认同)

Jon*_*eet 29

不,你不能.如果你看到我的意思(即必须满足所有约束条件),通用约束总是"与"对,所以即使你试图使用一些未密封的类,这仍然会失败.

你为什么要这样做?也许还有另一种方法可以更好地发挥作用.

  • @Poz:我建议动态地在SQL中添加足够的占位符,然后将它们指定为参数值.直接包括这些价值风险太大,IMO. (3认同)
  • @Poz:鉴于我一开始不会将值格式化为 SQL,我建议重构以使用参数化查询...... (2认同)
  • @Poz:我的意思是如果你有两个参数,你创建一个IN子句`IN(?,?)`或`IN(:p1,:p2)`或者其他什么,然后动态地将这些参数值添加到命令中以正常的方式.即使SQL是动态的,也不意味着你必须避免使用参数.还有其他替代方法,如表值参数(http://msdn.microsoft.com/en-us/library/bb510489.aspx),具体取决于您使用的SQL Server版本. (2认同)

Sea*_* C. 15

我使用了一个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>
Run Code Online (Sandbox Code Playgroud)

您可以使用IComparable,IConvertible,IEquatable<T>约束.像这样:

 public static void SetValue<T>(T value) where T : IComparable, IConvertible, IEquatable<T>
    {
        //TODO:
    }
Run Code Online (Sandbox Code Playgroud)

或者您可以使用类型代码来检查数据时间而不受约束.

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();
        }
    }
Run Code Online (Sandbox Code Playgroud)

请记住,不要使用对象类型,而是使用泛型类型作为参数类型.否则,Type.GetTypeCode(value.GetType())当值为null时,您可能会在代码行处获得NULL EXCEPTION .