¿Cuál es la diferencia entre System.Type y System.RuntimeType en C #?

89

Estaba tratando de hacer algunas pruebas de convención hoy, y obteniendo todos los tipos en una asamblea (llamando Assembly.GetTypes()), cuando tropecé con algo:

System.RuntimeType:[First.Namespace.FirstClass]

Siempre que trato de comparar ese tipo con typeof(FirstClass), no son iguales. Entonces, cuando trato de encontrar todos los tipos que contienen FirstClasscomo parámetro genérico, no encuentro ninguno.

¿Cuál es la diferencia entre System.RuntimeTypey System.Type?

¿Hay alguna forma de solucionar mi problema?

Edgar González
fuente
6
¿Puede proporcionar un pequeño programa que demuestre el problema que está experimentando?
Eric Lippert
Iba a hacerlo, pero ya obtuve la respuesta: P
Edgar Gonzalez

Respuestas:

108

System.RuntimeTypees una clase concreta que se deriva de la clase base abstracta System.Type. Dado System.RuntimeTypeque no es público, normalmente encontrará instancias como System.Type.

La confusión puede surgir cuando intenta obtener el tipo de un objeto y llama GetType()por error a otro objeto que representa el tipo del primer objeto, en lugar de usar ese objeto directamente. Luego Type.ToString()regresará "System.RuntimeType"cuando el objeto al que se llama esté representando un Tipo:

string str = string.Empty;
Type strType = str.GetType();
Type strTypeType = strType.GetType();
strType.ToString();     // returns "System.string"
strTypeType.ToString(); // returns "System.RuntimeType"

Por ejemplo, en esta publicación de blog, alguien está tratando de obtener el tipo de columna en una base de datos, haciendo algo como esto:

object val = reader.GetFieldType(index);
Type runtimeType = val.GetType();
PropertyInfo propInfo = runtimeType.GetProperty("UnderlyingSystemType");
Type type = (Type)propInfo.GetValue(val, null);

Dado que val ya es un objeto Type, val.GetType () devolverá otro objeto Type que representa el tipo, System.RuntimeTimeya que este es el tipo concreto utilizado para representar el objeto tipo original. La publicación del blog luego muestra algunos trucos de reflexión innecesarios, para obtener el tipo de objeto de tipo original, cuando en realidad todo lo que se requería era:

Type type = reader.GetFieldType(index) as Type;

Por lo tanto, si su Typeobjeto informa que representa a System.RuntimeType, asegúrese de no haber llamado accidentalmente GetType()a un tipo que ya tiene.

Ergwun
fuente
El primer fragmento de código solo verifica si el objeto es una instancia de Type; devolverá verdadero incluso si pasa typeof(int). El segundo fragmento de código no funciona para comparar typeof(string).GetType()y typeof(Type).
Mark Cidade
¡Esto es exactamente lo que estaba buscando! Encontré la publicación de Thomas Danecker pero no la de Doogal Bell
Edgar Gonzalez
1
@Mark Cidade. Bien visto, gracias. Tengo una respuesta fija para ser más útil, con suerte aclarando cualquier confusión que presenté al citar esa publicación de blog.
Ergwun
@Edgar Gonzalez: Esa publicación de blog a la que hice referencia fue en realidad bastante engañosa. Consulte mi respuesta actualizada para obtener mejor información.
Ergwun
4

De la respuesta a Diferente entre System.Type y System.RuntimeType de Thomas Danecker :

System.Type es una clase base abstracta. El CLR tiene su implementación concreta en el tipo interno System.RuntimeType. Debido a este typeof (string) .GetType () devuelve un RuntimeType pero typeof (Type) devuelve un Type normal. El uso del método .Equals hace de hecho un object.ReferenceEquals que devuelve falso. Para obtener los resultados esperados, puede usar type.IsInstanceOfType (element). Esto también devolverá verdadero si el elemento es de un tipo derivado. Si desea verificar el tipo exacto, el valor de retorno falso de su método es el resultado deseado. También puede usar checkType (arrayType, Type.GetType ("System.RuntimeType")) para verificar el RuntimeType.

John Saunders
fuente
1
"does in fact an" - ¿Podemos obtener una corrección gramatical? Esto es como el meollo de todo y no tiene sentido.
N73k
2

En breve...

    "".GetType().ToString()           == "System.String"

    "".GetType().GetType().ToString() == "System.RuntimeType"

La forma en que lo pienso ahora es que System.Typees un tipo base para el tipo que representa los resultados de la solicitud de tipo de objeto en tiempo de ejecución, es decir System.RuntimeType. Por lo tanto, cuando se solicita el tipo de un objeto, como en, "".GetType(), la instancia de System.Typeregresar es que es descendiente, System.RuntimeType. De hecho, uno debería esperar que también typeof(System.Type).GetType()lo sea System.RuntimeType, pero creo que el marco previene específicamente esta ... simetría.

Jorge
fuente