2011-09-26 13 views
9

¿hay una cláusula where para un genérico que determina que T es de tipo primitivo?C# restricción genérica donde no es clase?

void Method<T>(T val) where T : primitive 

caso:

tienen un lenguaje funcional escrito en C que se alimenta de tipos blitable no administrados primitivos, o cosas que pueden ser empujado en una primitiva con facilidad (por ejemplo, una fecha sin horas/minutos./seconds podría ser empujado a un int, etc.) El plan original era utilizar GPU. No haciendo eso sin embargo. C# se mantiene bien en su papel de coordinador hasta ahora. Tiendo a pensar que el hogar del esquema es vivir en C#. Esto no es estrictamente cierto, pero la idea sirve bien al proyecto.

Me gusta OO, pero cuando se trata de ideas funcionales, me gustaría restringir esos pensamientos a los tipos que son compatibles con ese dominio. Curiosamente, estoy todavía apoyándome en C# para ayudarme a mantenerme estructurado y disciplinado. No veo eso cambiando.


Hay otras razones por las que ser más detallado con las limitaciones sería una buena cosa para mí.

btw: resharper sugirió interfaces explícitas que probé por un tiempo. Me gustó mucho esta notación ... y las restricciones también pueden vivir con la interfaz. Bonito. Sin embargo, me encontré con la advertencia de Jon Skeet en S/O sobre esta herencia desordenada. Por lo tanto, volvamos a AssertIsXYZ, un tiempo de ejecución mucho más intenso.

Para llevar eso un poco más lejos, donde las limitaciones para mí son un paso hacia la prueba de la corrección (viejas ideas, pero aún buenas). El sistema de tipeo parece permitir que algo de esto sea enviado al compilador. Usar la palabra "dónde" hizo pensar en una cláusula o frase (como en SQL/LINQ). No estoy pidiendo que sea llevado al enésimo grado. Cuanto más trabajo haga el compilador, mejor en lo que a mí respecta.

Tener tacto con las limitaciones me ayudó a aclarar algunas ideas. Tengo que dar crédito allí ... pero es una pena que tuve que comentar las limitaciones después.

+0

¿No es todo en C# un objeto? – zellio

+0

Me interesa saber cuál es el uso. –

+0

¿Puedo preguntar por qué necesita esto? Desearía que los genéricos fueran más poderosos, pero por esto no veo la necesidad. – Carsten

Respuesta

6

Hay

where T : struct 

Eso es no el mismo que ser un tipo primitivo, que conste. Lo fuerza a ser un tipo de valor que no admite nulos. Eso incluiría, por ejemplo, Guid (que no es una primitiva) pero excluye Nullable<Guid> (que tampoco es una primitiva, pero también no es una clase).

Si puede ser más preciso acerca de sus requisitos, es posible que podamos ayudarle más.

+0

solo que es probable que T necesite ser blitable, es decir, ser representable como un tipo nativo. Tiene que ver con algunos calcos, y definir T de esta manera aclararía la intención. Puedo vivir sin eso, supongo. Donde T: struct incluiría int/short/bool/float/single/etc. – sgtz

+0

@sgtz: Esos son todos los tipos de valor que no admiten nulos, por lo que se incluirían, sí. –

2

No puede hacer esto (al menos actualmente). Si usted quiere que sea un tipo de valor:

void Method<T>(T val) where T : struct 

o se puede comprobar en tiempo de ejecución para asegurarse de que es muy primitiva (creo que quiere int/flotador/etc en lugar de todos los tipos de valor?)

public static class Ext 
{ 
    public static bool IsPrimitive(this Type t) 
    { 
     return t == typeof(int) || t == typeof(float) 
      || t == typeof(double) || ... 
    } 
} 

EDITAR LOL acaba de encontrar que hay una propiedad integrada en Type llamado IsPrimitive, eso es lo que voy a decir ...

7

No! No hay restricción para el tipo primitivo.

Su mejor opción en la aplicación de tipo primitivo es tan bajo:

void Method<T>(T val) where T:struct 
{ 
    if (!typeof(T).IsPrimitive) 
     throw new ArgumentException("Only primitive types are allowed.", "val"); 
} 

O

public void Method(int val) 
{ 
    GenericMethod(val); 
} 

public void Method(double val) 
{ 
    GenericMethod(val); 
} 

private void GenericMethod<T>(T val) where T:struct 
{ 
} 
+1

como la idea .Primitive. – sgtz

0

No hay, pero se puede utilizar struct restricción.

where T: struct 
0

Una restricción tiene que ser un tipo no sellado, por lo que no es una forma de restringir una genérico para un tipo primitivo.

19

Sospecho que lo que quiere sobre la base de sus comentarios sobre la respuesta de Jon es una manera de limitar un parámetro de tipo a cualquiera de los tipos blittable o tipos no administrados.

Un "tipo no gestionado" es un tipo cuya definición impide cualquier referencia a la memoria rastreada por el recolector de elementos no utilizados; solo puede crear tipos de punteros a partir de tipos no administrados. Los tipos blittables son aquellos que se pueden ordenar de código administrado a no administrado sin ninguna modificación en sus bits; son un subconjunto de los tipos no administrados.

Varias personas nos han dicho que sería muy útil tener una restricción genérica que constriñe un parámetro de tipo para que sea solo un tipo no administrado. Hemos experimentado con prototipos de C# y CLR que tienen esta restricción, pero no tenemos planes en este momento para poner realmente la característica en el producto. Si puede describir el escenario que motiva la solicitud de funciones, eso nos ayudaría a priorizar la función frente a las cientos de otras características que también son posibles.

+1

con esa restricción podríamos hacer un tamaño de (T) y obtener un valor constante de tiempo de jit? El único momento en que esto sería complejo sería si hubieras incrustado IntPtr y, si lo hiciste, la responsabilidad está en el codificador para saber lo que están haciendo, de todos modos. Del mismo modo, podría reinterpretar los moldes en C# a cualquier otro tipo de compilación conocido no manipulado (por un constriente similar o de otro modo). Eso eliminaría la necesidad de algunos aros molestos de C++/CLI que tenemos que saltar para trabajar eficientemente con enums, o blit arbitrarios genéricos que esperamos (lectura, comprobación de tiempo de ejecución, no compilación de verificación) no son administrados – ShuggyCoUk

+1

@ShuggyCoUk: Correcto. En nuestro prototipo, una de las características que teníamos era que "sizeof (T)" funcionaba de la forma deseada en un parámetro de tipo conocido de tipo blittable, se podía hacer un "puntero a T" para un parámetro de tipo genérico T, y así. –

+0

Eso sería realmente útil, ya que evitaría la molestia de caer a C++/CLI y evitaría errores de verificación de tiempo de compilación.Por supuesto, ahora tenemos las funciones de utilidad CPP funcionando muy bien, no es tan importante en términos de utilidad directa si estaba buscando directamente usar ese tipo de cosas. Tal vez sea útil poder hacer un stackalloc para ellos, pero he descubierto que los búferes de scratch preasignados que se pasan y fijados en los nodos de hojas del gráfico de llamadas realmente terminan siendo bastante buenos. – ShuggyCoUk

Cuestiones relacionadas