typeof(string).IsPrimitive == false
typeof(int).IsPrimitive == true
typeof(MyClass).IsClass == true
typeof(string).IsClass == true
typeof(string).IsByRef == false
typeof(MyClass).IsByRef == true //correction: should be false (see comments below)

Tengo un método que crea una nueva instancia de T y, si se trata de un «complejo» de la clase, llena sus propiedades a partir de un conjunto de datos de origen de los valores.

(a) Si T es un tipo simple (por ejemplo, una cadena o un entero o cualquier otra cosa similar), una conversión rápida de los datos de origen a T se va a realizar.

(b) Si T es una clase (pero no algo tan simple como cadena), entonces voy a usar el Activador.CreateInstance y hacer un poco de reflexión para rellenar los campos.

Hay una manera simple y rápida para saber si debo utilizar el método (a) o método (b)? Esta lógica va a ser utilizado dentro de un método genérico con T como el tipo de argumento.

  • la cadena, a pesar de tener un nombre en minúsculas en C#, no es un tipo simple, sino más bien una envoltura alrededor de una matriz de char. cadena se convierte a Cadena internamente el compilador de C#.
  • Tengo curiosidad — ¿cómo se puede conseguir que la última línea de resultado en verdadera?
  • debido a que las instancias de una clase se pasan por referencia…
  • en el momento en que escribió el comentario anterior, yo no tenía idea de quiénes eran. Habiendo olvidado todo acerca de esta cuestión, me encontré con él de nuevo y se dio cuenta de mi frívola respuesta a su pregunta y se dio cuenta de que estaba tratando, lo que significa que obviamente estoy mal 😉
  • IsByRef es para la siguiente situación: usted tiene un MethodInfo para el método void A(ref int x); obtener el ParameterInfo para x y preguntar por el tipo del parámetro. El IsByRef propiedad de que Type debe ser true. El GetElementType método devuelve typeof(int). No puedo pensar en una manera de utilizar typeof(C) y obtener un parámetro ref tipo de que, de ahí mi pregunta.
  • Su suposición de que IsByRef le indica si un valor de un tipo que se pasa por referencia es claramente incorrecta porque usted declaró que IsByRef fue false para string, pero es evidente que las cadenas se pasan por referencia. Para saber si un tipo se pasa por referencia o por valor debe utilizar IsValueType.
  • gracias, que hace perfecto sentido

7 Comentarios

  1. 111

    Cadena es probablemente un caso especial.

    Creo que me gustaría hacer…..

    bool IsSimple(Type type)
    {
        return type.IsPrimitive 
          || type.Equals(typeof(string));
    }

    Edición:

    A veces se necesita para cubrir algunos de los más de los casos, como las enumeraciones y los decimales. Las enumeraciones son un tipo especial de tipo en C#. Los decimales son estructuras como cualquier otro. El problema con las estructuras es que pueden ser complejas, que pueden ser de tipos definidos por el usuario, pueden ser sólo un número. Así que usted no tiene ninguna otra posibilidad de conocer a diferenciar.

    bool IsSimple(Type type)
    {
      return type.IsPrimitive 
        || type.IsEnum
        || type.Equals(typeof(string))
        || type.Equals(typeof(decimal));
    }

    Manejo que aceptan valores null homólogos son también un poco difícil. El que acepta valores null en sí es una estructura.

    bool IsSimple(Type type)
    {
      if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
      {
        //nullable type, check if the nested type is simple.
        return IsSimple(type.GetGenericArguments()[0]);
      }
      return type.IsPrimitive 
        || type.IsEnum
        || type.Equals(typeof(string))
        || type.Equals(typeof(decimal));
    }

    Prueba:

    Assert.IsTrue(IsSimple(typeof(string)));
    Assert.IsTrue(IsSimple(typeof(int)));
    Assert.IsTrue(IsSimple(typeof(decimal)));
    Assert.IsTrue(IsSimple(typeof(float)));
    Assert.IsTrue(IsSimple(typeof(StringComparison)));  //enum
    Assert.IsTrue(IsSimple(typeof(int?)));
    Assert.IsTrue(IsSimple(typeof(decimal?)));
    Assert.IsTrue(IsSimple(typeof(StringComparison?)));
    Assert.IsFalse(IsSimple(typeof(object)));
    Assert.IsFalse(IsSimple(typeof(Point)));  //struct in System.Drawing
    Assert.IsFalse(IsSimple(typeof(Point?)));
    Assert.IsFalse(IsSimple(typeof(StringBuilder))); //reference type

    Nota .NET Core

    Como DucoJ señala en su respuesta, algunos de los métodos utilizados no están disponibles en la clase Type en .NET core más.

    Código fijo (espero que funcione, yo no podía probar a mí mismo. De lo contrario, por favor comente):

    bool IsSimple(Type type)
    {
      var typeInfo = type.GetTypeInfo();
      if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>))
      {
        //nullable type, check if the nested type is simple.
        return IsSimple(typeInfo.GetGenericArguments()[0]);
      }
      return typeInfo.IsPrimitive 
        || typeInfo.IsEnum
        || type.Equals(typeof(string))
        || type.Equals(typeof(decimal));
    }
    • John Saunders, a continuación, hace un punto válido, por lo que en la luz yo creo que tu respuesta es probablemente la mejor para mi caso.
    • Esta falla por cosas como las enumeraciones, los decimales, etc. Véase mi respuesta a continuación para una solución más general
    • doble es también «primitivo», según docs.microsoft.com/en-us/dotnet/api/…
    • Sí, lo es. ¿Qué quieres decir con eso? Yo no la lista de todos los tipos primitivos en las «pruebas», una selección de un par de casos diferentes. double es el mismo que float, int, bool, long, ‘byte` y así sucesivamente. Casos especiales son decimal, string y enumeraciones que no son primitivos, pero todavía se consideran normalmente como «simple» tipos».
    • De acuerdo a ese enlace IsPrimative es cierto para double. Así que no es «especial» y no es necesario la prueba adicional en IsSimple. a la derecha?
    • sí, eso es correcto.
    • Dependiendo de sus necesidades, usted puede ser que necesite para agregar || tipo.Es igual a(typeof(datetime))
    • Así como || type.Equals(typeof(TimeSpan)).
    • También, tenga en cuenta que .Net Core apoya la .Net Type de nuevo a la facilidad de la portabilidad.

  2. 16

    Además de Stefan Steinegger respuesta:
    En .RED de Núcleo de el .IsPrimitive etc. no son miembros de Tipo, son ahora miembros de TypeInfo. Así que su solución será entonces:

    bool IsSimple(TypeInfo type)
    {
        if (type.IsGenericType && type.GetGenericTypeDefinition() ==     typeof(Nullable<>))
        {
            //nullable type, check if the nested type is simple.
            return IsSimple((type.GetGenericArguments()[0]).GetTypeInfo());
        }
        return type.IsPrimitive
          || type.IsEnum
          || type.Equals(typeof(string))
          || type.Equals(typeof(decimal));
    }
    • Si alguien con suficiente rep podría publicar esto como un comentario bajo Stefan Steinegger del post, puede que seguro que otras personas de tiempo.
    • Al menos en la versión de netstandard estoy usando (1.6) type.Equals(typeof(x)) resultados en un error de compilación porque el type variable es una System.Reflection.TypeInfo, que no no se derivan de System.Type. En su lugar tienes que utilizar type.Equals(typeof(x).GetTypeInfo()).
    • Gracias por este. Yo no sabía que. He añadido esta información a mi respuesta.
  3. 6

    Hay un tipo más general de la primitiva, el tipo de valor abarca mucho más que primitivos, tales como las enumeraciones, decimal, y otras cosas ValueType. A continuación es una función que le escribí a identificar los tipos complejos, que pueden ajustarse a sus necesidades.

        public static bool IsComplex(Type typeIn)
        {
            if (typeIn.IsSubclassOf(typeof(System.ValueType)) || typeIn.Equals(typeof(string))) //|| typeIn.IsPrimitive
                return false;
            else
                return true;
    
        }
    • También hay typeIn.IsValueType. «IsComplex» es engañoso en este caso, debido a una estructura (tipo de valor) puede ser complejo por tener muchas propiedades, que, por ejemplo, puede señalar a los tipos de referencia.
    • He mejorado mi respuesta. No hay una sola respuesta correcta a esta cuestión, ya que depende mucho de lo que se necesita en el caso concreto. A veces usted puede manejar todos los tipos de valor de la misma, a veces no se puede.
  4. 3

    Lo siento para resucitar a un muy viejo hilo, pero ya que este todavía se encuentra de alta en la web de búsquedas en Google, quiere conseguir de una manera más directa y efectiva solución añadido:

    if(System.Type.GetTypeCode(typeof(int)) == TypeCode.Object) {
        //Do what you will...
    }
    • Usted debe explicar un poco mejor lo que está pasando aquí, es decir, por lo que realizar las comprobaciones es útil.
    • Cuando System.Type.GetTypeCode(typeof(myValue)) es TypeCode.Object, «mivalor» no es un tipo primitivo. Otra cosa que hay una docena de diferentes tipos primitivos. msdn.microsoft.com/en-us/library/system.typecode(v=vs 110).aspx
    • Esto no funciona tan bien para Nullables…. >System.Type.GetTypeCode(typeof(int?)) >Object
  5. 1

    Puede no importar, pero suena como que usted está dejando fuera a un par de casos:

    1. Tipos complejos que han conversiones
    2. Tipos de valor que no tiene un constructor sin parámetros. Ejemplo a continuación:

    Probablemente hay más, pero creo que tienes particionado el problema de espacio en un muy restrictiva manera.

     public class Person {
        private string _name;
        private int _age;
        public Person(string name, int age) {_name = name; _age = age;}
        //Remainder of value implementation
     }
    • Me podría dar un ejemplo de caso #2?
    • Structs siempre tienen implícito un constructor sin parámetros. Siempre se puede obtener un valor predeterminado con default(MyStruct). Consulte msdn.microsoft.com/en-us/library/aa288208%28v=vs.71%29.aspx
    • ¿sabía usted que usted ha publicado una .NET 1.1 enlace?
    • Es el primer resultado de la búsqueda en google para «Struct Constructores» 🙂 sin Embargo, no cambió desde entonces. Hay un nuevo link: msdn.microsoft.com/en-us/library/0taef578.aspx
    • El problema con los enlaces viejos es que contienen otros enlaces viejos, y los incautos pueden encontrarse perdido en el pasado lejano inocentemente siguientes enlaces. Gracias por el link actualizado.
  6. 0

    Cadenas no son primitivos, si recuerdo correctamente. aunque no es una palabra clave para que, una cadena es un objeto. Su llamada a IsPrimitive se precisa indicar si algo es una primitiva.

    • Sí, pero las cadenas son asignados como primitivas y en la mayoría de los casos son tratados (desde el exterior) como si son primitivas.
    • Las cadenas son una especie de un único bestia en este sentido. Creo que Stefan la sugerencia de manejo especial para ellos es el mejor enfoque.
  7. 0

    Modificado Mauser la respuesta de un poco añadido un método para comprobar si una propiedad es una colección.

    public static class TypeExtensions
    {
        public static bool IsComplex(this Type type)
        {
            return !type.IsValueType && type != typeof(string);
        }
    
        public static bool IsCollection(this Type type)
        {
            var collectionTypeName = typeof(ICollection<>).Name;
            return type.Name == collectionTypeName || type.GetInterface(collectionTypeName) != null;
        }
    }

    Aquí dentro IsCollection(..) incluso podemos mantener IEnumerable, pero la cadena también heredan IEnumerable. así que si usted está utilizando IEnumerable, agregar una comprobación de cadena también!

    public static class TypeExtensions
    {
    public static bool IsComplex(this Type type)
    {
    return !type.IsValueType && type != typeof(string);
    }
    public static bool IsCustomComplex(this Type type)
    {
    var elementType = type.GetCustomElementType();
    return elementType != null && elementType.IsComplex();
    }
    public static Type GetCustomElementType(this Type type, object value)
    {
    return value != null 
    ? value.GetType().GetCustomElementType() 
    : type.GetCustomElementType();
    }
    public static Type GetCustomElementType(this Type type)
    {
    return type.IsCollection()
    ? type.IsArray
    ? type.GetElementType()
    : type.GetGenericArguments()[0]
    : type;
    }
    public static bool IsCustomComplex(this Type type, object value)
    {
    return value != null
    ? value.GetType().IsCustomComplex()
    : type.IsCustomComplex();
    }
    public static bool IsCollection(this Type type)
    {
    var collectionTypeName = typeof(IEnumerable<>).Name;
    return (type.Name == collectionTypeName || type.GetInterface(typeof(IEnumerable<>).Name) != null ||
    type.IsArray) && type != typeof(string);
    }
    public static bool HasDefaultConstructor(this Type type)
    {
    return type.IsValueType || type.GetConstructor(Type.EmptyTypes) != null;
    }
    }

Dejar respuesta

Please enter your comment!
Please enter your name here