eticos - enum class c#
C#Restricciones genéricas para incluir tipos de valores Y cadenas (5)
Estoy intentando escribir un método de extensión en IEnumerable que solo se aplicará a los tipos de valores y cadenas.
public static string MyMethod<T>(this IEnumerable<T> source) where T : struct, string
Sin embargo, ''cadena'' no es una restricción válida ya que es una clase sellada.
¿Hay alguna manera de hacer esto?
Editar:
Lo que en realidad estoy tratando de hacer es preparar una lista de valores para una cláusula "IN" en un SQL construido dinámicamente.
Tengo muchas instancias de código como las siguientes que quiero limpiar:
sb.AppendLine(string.Format("AND value IN ({0})", string.Join(",", Values.Select(x => x.ToSQL()).ToArray())));
Donde ToSQL () tiene código para manejar SqlInjection.
¿Tal vez podría restringir a tipos IConvertible? Todas las primitivas del sistema que se pueden convertir utilizando estos métodos de interfaz también implementan la interfaz, por lo que esta restricción requeriría que T sea una de las siguientes:
- Booleano
- Byte
- Carbonizarse
- Fecha y hora
- Decimal
- Doble
- Int (16, 32 y 64 bits)
- SByte
- Individual (flotador)
- Cuerda
- UInt (16, 32 y 64 bits)
Si tiene un IConvertible, es muy probable que sea uno de estos tipos, ya que la interfaz IConvertible es tan complicada de implementar que rara vez se realiza para los tipos de terceros.
El inconveniente principal es que sin convertir realmente T a una instancia de uno de estos tipos, todo lo que su método sabrá hacer es llamar al Objeto y a los métodos IConvertibles, o métodos que toman un Objeto o IConvertible. Si necesita algo más (como la capacidad de agregar y / o concatenar usando +), creo que simplemente establecer dos métodos, uno genérico para tipos de estructura y otro fuertemente tipado para cadenas, sería la mejor opción en general.
Necesita definir 2 métodos separados:
public static string MyMethod<T>(this IEnumerable<T> source) where T : struct
public static string MyMethod(this IEnumerable<string> source)
No, no puedes. Las restricciones genéricas siempre son "AND" -ed, si ves lo que quiero decir (es decir, todas las restricciones deben ser satisfechas), incluso si intentaras utilizar alguna clase no sellada, esto aún fallaría.
¿Por qué quieres hacer esto? Tal vez haya otro enfoque que funcione mejor.
Puede usar un constructor estático para verificar el parámetro de tipo cuando se usa la clase.
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.");
}
}
}
Usé una solución de hack: interfaz. Vea las interfaces que han implementado los tipos de valores incorporados y el tipo de cadena:
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>
Puede usar IComparable,IConvertible,IEquatable<T>
para las restricciones. Me gusta esto:
public static void SetValue<T>(T value) where T : IComparable, IConvertible, IEquatable<T>
{
//TODO:
}
O puede usar el código de tipo para verificar la hora de los datos sin restricciones.
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();
}
}
Recuerde que no use el tipo de objeto sino el tipo genérico para el tipo de parámetro. De lo contrario, podría obtener una EXCEPCIÓN NULA en la línea de código Type.GetTypeCode(value.GetType())
cuando el valor sea nulo.