uso usando tipos tipo requiere parametros parametro objeto metodos lista genericos generico generica ejemplos crear como argumentos c# generics primitive type-safety

c# - usando - Comprobación de tipo genérico



tipos genericos en c# (8)

@Rob, Enum pasará por la función TypeValid ya que TypeCode es Integer . Actualicé la función para verificar también Enum .

Private Function TypeValid() As Boolean Dim g As Type = GetType(T) Dim code As TypeCode = Type.GetTypeCode(g) '' All of the TypeCode Enumeration refer Primitive Types '' with the exception of Object and Empty (Nothing). '' Note: must also catch Enum as its type is Integer. Select Case code Case TypeCode.Object Return False Case Else '' Enum''s TypeCode is Integer, so check BaseType If g.BaseType Is GetType(System.Enum) Then Return False Else Return True End If End Select End Function

¿Hay alguna manera de aplicar / limitar los tipos que se pasan a los primitivos? (bool, int, cadena, etc.)

Ahora, sé que puede limitar el parámetro de tipo genérico a una implementación de tipo o interfaz a través de la cláusula where . Sin embargo, esto no se ajusta a la factura de primitivos (AFAIK) porque no todos tienen un terreno común (¡aparte del objeto antes de que alguien diga!: P).

Entonces, mis pensamientos actuales son apretar los dientes y hacer una gran declaración de cambio y arrojar una ArgumentException sobre una falla.

EDIT 1:

Solo para aclarar:

La definición del código debe ser como:

public class MyClass<GenericType> ....

Y instanciación:

MyClass<bool> = new MyClass<bool>(); // Legal MyClass<string> = new MyClass<string>(); // Legal MyClass<DataSet> = new MyClass<DataSet>(); // Illegal MyClass<RobsFunkyHat> = new MyClass<RobsFunkyHat>(); // Illegal (but looks awesome!)

EDIT 2

@Jon Limjap - Buen punto, y algo que ya estaba considerando ... Estoy seguro de que hay un método genérico que se puede usar para determinar si el tipo es de un valor o tipo de referencia.

Esto podría ser útil para eliminar al instante muchos de los objetos con los que no quiero lidiar (pero debes preocuparte por las estructuras que se usan, como el Tamaño ). ¿Problema interesante, no? :)

Aquí está:

where T : struct

Tomado de MSDN .

Tengo curiosidad ... ¿Podría hacerse esto en .NET 3.x usando métodos de extensión? Cree una interfaz e implemente la interfaz en los métodos de extensión (que probablemente sería más limpio que un conmutador de poca grasa). Además, si luego necesita extenderse a cualquier tipo personalizado liviano, también pueden implementar la misma interfaz, sin cambios requeridos en el código base.

¿Qué piensan ustedes?

Triste noticia es que estoy trabajando en Framework 2 !! :RE

EDIT 3

Esto fue tan simple como seguir a Jon Limjaps Pointer . Tan simple que casi quiero llorar, ¡pero es genial porque el código funciona como un hechizo!

Así que aquí está lo que hice (¡te reirás!):

Código agregado a la clase genérica

bool TypeValid() { // Get the TypeCode from the Primitive Type TypeCode code = Type.GetTypeCode(typeof(PrimitiveDataType)); // All of the TypeCode Enumeration refer Primitive Types // with the exception of Object and Empty (Null). // Since I am willing to allow Null Types (at this time) // all we need to check for is Object! switch (code) { case TypeCode.Object: return false; default: return true; } }

Luego, un pequeño método de utilidad para verificar el tipo y lanzar una excepción,

private void EnforcePrimitiveType() { if (!TypeValid()) throw new InvalidOperationException( "Unable to Instantiate SimpleMetadata based on the Generic Type of ''" + typeof(PrimitiveDataType).Name + "'' - this Class is Designed to Work with Primitive Data Types Only."); }

Todo lo que hay que hacer es llamar a EnforcePrimitiveType () en los constructores de las clases. ¡Trabajo hecho! :-)

La única desventaja es que arroja una excepción en tiempo de ejecución (obviamente) en lugar de tiempo de diseño. Pero eso no es gran cosa y podría ser recogido con utilidades como FxCop (que no usamos en el trabajo).

Un agradecimiento especial a Jon Limjap en este caso!


Al tener un desafío similar, me preguntaba cómo se sentían ustedes acerca de la interfaz IConvertible . Permite lo que el solicitante requiere y puede extenderse con sus propias implementaciones.

Ejemplo:

public class MyClass<TKey> where TKey : IConvertible { // class intentionally abbreviated }

Estoy pensando en esto como una solución, aunque muchos de los sugeridos también fueron parte de mi selección.

Mi preocupación es, sin embargo, ¿es engañoso para los desarrolladores potenciales que usan su clase?

Saludos, y gracias.


Los primitivos parecen estar especificados en la enumeración de TypeCode :

Quizás haya una forma de averiguar si un objeto contiene la TypeCode enum sin tener que convertirlo en un objeto específico o llamar a GetType() o typeof() ?

Actualización Fue justo debajo de mi nariz. El ejemplo del código muestra esto:

static void WriteObjectInfo(object testObject) { TypeCode typeCode = Type.GetTypeCode( testObject.GetType() ); switch( typeCode ) { case TypeCode.Boolean: Console.WriteLine("Boolean: {0}", testObject); break; case TypeCode.Double: Console.WriteLine("Double: {0}", testObject); break; default: Console.WriteLine("{0}: {1}", typeCode.ToString(), testObject); break; } } }

Sigue siendo un interruptor feo. ¡Pero es un buen lugar para comenzar!


Más o menos lo que @Lars ya dijo:

//Force T to be a value (primitive) type. public class Class1<T> where T: struct //Force T to be a reference type. public class Class1<T> where T: class //Force T to be a parameterless constructor. public class Class1<T> where T: new()

Todo funciona en .NET 2, 3 y 3.5.



Si puede tolerar el uso de métodos de fábrica (en lugar de los constructores MyClass que solicitó), siempre podría hacer algo como esto:

class MyClass<T> { private readonly T _value; private MyClass(T value) { _value = value; } public static MyClass<int> FromInt32(int value) { return new MyClass<int>(value); } public static MyClass<string> FromString(string value) { return new MyClass<string>(value); } // etc for all the primitive types, or whatever other fixed set of types you are concerned about }

Un problema aquí es que tendría que escribir MyClass<AnyTypeItDoesntMatter>.FromInt32 , que es molesto. No hay una forma muy buena de evitar esto si desea mantener el carácter privado del constructor, pero aquí hay un par de soluciones:

  • Crea una clase abstracta MyClass . Haga que MyClass<T> herede de MyClass y MyClass dentro de MyClass . Mueva los métodos estáticos a MyClass . Esto hará que toda la visibilidad funcione, a costa de tener que acceder a MyClass<T> como MyClass.MyClass<T> .
  • Use MyClass<T> como se indica. Cree una clase estática MyClass que invoque los métodos estáticos en MyClass<T> utilizando MyClass<AnyTypeItDoesntMatter> (probablemente use el tipo apropiado cada vez, solo para risitas).
  • (Más fácil, pero ciertamente raro) Haga un tipo abstracto MyClass que hereda de MyClass<AnyTypeItDoesntMatter> . (Para ser concretos, digamos MyClass<int> .) Debido a que puede llamar a métodos estáticos definidos en una clase base a través del nombre de una clase derivada, ahora puede usar MyClass.FromString .

Esto le da una comprobación estática a expensas de más escritura.

Si está satisfecho con la comprobación dinámica, usaría alguna variación en la solución de TypeCode anterior.


Utilice una regla FxCop personalizada que FxCop uso indeseable de MyClass<> .


public class Class1<GenericType> where GenericType : struct { }

Este parecía hacer el trabajo ...