c# - Cómo probar si el tipo es primitivo
reflection primitive-types (12)
Acabo de encontrar esta pregunta mientras buscaba una solución similar, y pensé que podría estar interesado en el siguiente enfoque utilizando System.TypeCode
y System.Convert
.
Es fácil serializar cualquier tipo que esté mapeado en un System.TypeCode
no sea System.TypeCode.Object
, por lo que podría hacer:
object PropertyValue = ...
if(Convert.GetTypeCode(PropertyValue) != TypeCode.Object)
{
string StringValue = Convert.ToString(PropertyValue);
...
}
La ventaja de este enfoque es que no tiene que nombrar cualquier otro tipo no primitivo aceptable. También puede modificar ligeramente el código anterior para manejar cualquier tipo que implemente IConvertible.
Tengo un bloque de código que serializa un tipo en una etiqueta Html.
Type t = typeof(T); // I pass <T> in as a paramter, where myObj is of type T
tagBuilder.Attributes.Add("class", t.Name);
foreach (PropertyInfo prop in t.GetProperties())
{
object propValue = prop.GetValue(myObj, null);
string stringValue = propValue != null ? propValue.ToString() : String.Empty;
tagBuilder.Attributes.Add(prop.Name, stringValue);
}
Esto funciona muy bien, excepto que quiero que solo haga esto para tipos primitivos, como int
, double
, bool
, etc., y otros tipos que no son primitivos, pero que se pueden serializar fácilmente como string
. Quiero que ignore todo lo demás, como listas y otros tipos personalizados.
¿Alguien puede sugerir cómo hago esto? ¿O debo especificar los tipos que quiero permitir en algún lugar y activar el tipo de propiedad para ver si está permitido? Eso es un poco desordenado, así que estaría bien si hubiera una manera más ordenada.
Aquí hay otra opción viable.
public static bool CanDirectlyCompare(Type type)
{
return typeof(IComparable).IsAssignableFrom(type) || type.IsPrimitive || type.IsValueType;
}
Así es como lo hice.
static class PrimitiveTypes
{
public static readonly Type[] List;
static PrimitiveTypes()
{
var types = new[]
{
typeof (Enum),
typeof (String),
typeof (Char),
typeof (Guid),
typeof (Boolean),
typeof (Byte),
typeof (Int16),
typeof (Int32),
typeof (Int64),
typeof (Single),
typeof (Double),
typeof (Decimal),
typeof (SByte),
typeof (UInt16),
typeof (UInt32),
typeof (UInt64),
typeof (DateTime),
typeof (DateTimeOffset),
typeof (TimeSpan),
};
var nullTypes = from t in types
where t.IsValueType
select typeof (Nullable<>).MakeGenericType(t);
List = types.Concat(nullTypes).ToArray();
}
public static bool Test(Type type)
{
if (List.Any(x => x.IsAssignableFrom(type)))
return true;
var nut = Nullable.GetUnderlyingType(type);
return nut != null && nut.IsEnum;
}
}
Asumiendo que tienes una firma de función como esta:
void foo<T>()
Puede agregar una restricción genérica para permitir solo los tipos de valor:
void foo<T>() where T : struct
Tenga en cuenta que esto permite no solo tipos primitivos para T, sino también cualquier tipo de valor.
Desde @Ronnie Overby response y @jonathanconway comment, escribí este método que funciona para Nullable y excluyo las estructuras de usuario.
public static bool IsSimpleType(Type type)
{
return
type.IsPrimitive ||
new Type[] {
typeof(Enum),
typeof(String),
typeof(Decimal),
typeof(DateTime),
typeof(DateTimeOffset),
typeof(TimeSpan),
typeof(Guid)
}.Contains(type) ||
Convert.GetTypeCode(type) != TypeCode.Object ||
(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) && IsSimpleType(type.GetGenericArguments()[0]))
;
}
Con el siguiente TestCase:
struct TestStruct
{
public string Prop1;
public int Prop2;
}
class TestClass1
{
public string Prop1;
public int Prop2;
}
[Test]
public void Test1()
{
Assert.IsTrue(IsSimpleType(typeof(Enum)));
Assert.IsTrue(IsSimpleType(typeof(String)));
Assert.IsTrue(IsSimpleType(typeof(Char)));
Assert.IsTrue(IsSimpleType(typeof(Guid)));
Assert.IsTrue(IsSimpleType(typeof(Boolean)));
Assert.IsTrue(IsSimpleType(typeof(Byte)));
Assert.IsTrue(IsSimpleType(typeof(Int16)));
Assert.IsTrue(IsSimpleType(typeof(Int32)));
Assert.IsTrue(IsSimpleType(typeof(Int64)));
Assert.IsTrue(IsSimpleType(typeof(Single)));
Assert.IsTrue(IsSimpleType(typeof(Double)));
Assert.IsTrue(IsSimpleType(typeof(Decimal)));
Assert.IsTrue(IsSimpleType(typeof(SByte)));
Assert.IsTrue(IsSimpleType(typeof(UInt16)));
Assert.IsTrue(IsSimpleType(typeof(UInt32)));
Assert.IsTrue(IsSimpleType(typeof(UInt64)));
Assert.IsTrue(IsSimpleType(typeof(DateTime)));
Assert.IsTrue(IsSimpleType(typeof(DateTimeOffset)));
Assert.IsTrue(IsSimpleType(typeof(TimeSpan)));
Assert.IsFalse(IsSimpleType(typeof(TestStruct)));
Assert.IsFalse(IsSimpleType(typeof(TestClass1)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<Char>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<Guid>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<Boolean>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<Byte>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<Int16>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<Int32>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<Int64>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<Single>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<Double>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<Decimal>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<SByte>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<UInt16>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<UInt32>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<UInt64>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<DateTime>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<DateTimeOffset>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<TimeSpan>)));
Assert.IsFalse(IsSimpleType(typeof(Nullable<TestStruct>)));
}
Esto es lo que tengo en mi biblioteca. Los comentarios son bienvenidos
Primero compruebo IsValueType, ya que maneja la mayoría de los tipos, luego String, ya que es el segundo más común. No puedo pensar en un primitivo que no sea un tipo de valor, así que no sé si ese tramo del si alguna vez es golpeado.
Public Shared Function IsPersistable(Type As System.Type) As Boolean
With TypeInformation.UnderlyingType(Type)
Return .IsValueType OrElse Type = GetType(String) OrElse .IsPrimitive
End With
End Function
Public Shared Function IsNullable(ByVal Type As System.Type) As Boolean
Return (Type.IsGenericType) AndAlso (Type.GetGenericTypeDefinition() Is GetType(Nullable(Of )))
End Function
Public Shared Function UnderlyingType(ByVal Type As System.Type) As System.Type
If IsNullable(Type) Then
Return Nullable.GetUnderlyingType(Type)
Else
Return Type
End If
End Function
Entonces puedo usarlo así:
Public Shared Function PersistableProperties(Item As System.Type) As IEnumerable(Of System.Reflection.PropertyInfo)
Return From PropertyInfo In Item.GetProperties()
Where PropertyInfo.CanWrite AndAlso (IsPersistable(PropertyInfo.PropertyType))
Select PropertyInfo
End Function
Lo hacemos así en nuestro ORM:
Type t;
bool isPrimitiveType = t.IsPrimitive || t.IsValueType || (t == typeof(string));
Sé que usar IsValueType
no es la mejor opción (puedes tener tus propias estructuras muy complejas) pero funciona en 99% de los casos
Puede usar la propiedad Type.IsPrimitive
, pero tenga cuidado porque hay algunos tipos que podemos pensar que son primitivos, pero no lo son, por ejemplo, Decimal
y String
.
Edición 1: código de muestra agregado
Aquí hay un código de muestra:
if (t.IsPrimitive || t == typeof(Decimal) || t == typeof(String) || ... )
{
// Is Primitive, or Decimal, or String
}
Editar 2: como comentarios de SLaks , hay otros tipos que quizás desee tratar como primitivos, también. Creo que tendrás que agregar estas variaciones una a una .
Edición 3: IsPrimitive = (Booleano, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Doble y Único), tipo Anther Primitive-Like para verificar (t == typeof (DateTime) )
Solo quiero compartir mi solución. Tal vez sea útil para cualquiera.
public static bool IsPrimitiveType(Type fieldType)
{
return fieldType.IsPrimitive || fieldType.Namespace.Equals("System");
}
También una buena posibilidad:
private static bool IsPrimitiveType(Type type)
{
return (type == typeof(object) || Type.GetTypeCode(type) != TypeCode.Object);
}
Tenía la necesidad de serializar tipos para exportarlos a XML. Para hacer esto, itere a través del objeto y opté por campos primitivos, enum, value types o serializables. Este fue el resultado de mi consulta:
Type contextType = context.GetType();
var props = (from property in contextType.GetProperties()
let name = property.Name
let type = property.PropertyType
let value = property.GetValue(context,
(BindingFlags.GetProperty | BindingFlags.GetField | BindingFlags.Public),
null, null, null)
where (type.IsPrimitive || type.IsEnum || type.IsValueType || type.IsSerializable)
select new { Name = name, Value = value});
Usé LINQ para repetir los tipos, luego obtuve su nombre y valor para almacenarlos en una tabla de símbolos. La clave está en la cláusula ''dónde'' que elegí para la reflexión. Elegí primitivos, enumerados, tipos de valores y tipos serializables. Esto permitió que las cadenas y los objetos DateTime aparecieran como esperaba.
¡Aclamaciones!
public static bool IsPrimitiveType(object myObject)
{
var myType = myObject.GetType();
return myType.IsPrimitive || myType.Namespace == null || myType.Namespace.Equals("System");
}
No olvides verificar el espacio de nombres NULL, porque los objetos anónimos no tienen espacio de nombres asignado