如何测试类型是否为基元类型

我有一段将类型序列化为 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);
}

这个工作非常好,除了我希望它只对基本类型执行此操作,如 intdoublebool等,以及其他非基本但可以很容易序列化的类型,如 string。我希望它忽略其他一切,如列表和其他自定义类型。

有人能告诉我该怎么做吗?还是需要指定要在某处允许的类型,然后打开属性的类型以查看是否允许?有点乱,所以如果我有更整洁的方式就好了。

106026 次浏览

您可以使用属性 Type.IsPrimitive,但要小心,因为有些类型我们可以认为是原语,但它们不是,例如 DecimalString

编辑1: < em > 添加了示例代码

下面是一个示例代码:

if (t.IsPrimitive || t == typeof(Decimal) || t == typeof(String) || ... )
{
// Is Primitive, or Decimal, or String
}

编辑2: 作为 @ Slaks注释,还有其他类型也可以作为原语处理。我认为你必须添加这个变体 一个接一个

编辑3: IsPrimitive = (Boolean,Byte,SByte,Int16,UInt16,Int32,UInt32,Int64,UInt64,IntPtr,UIntPtr,Char,Double 和 Single) , 需要检查的类基元类型(t = = typeof (DateTime))

假设您有这样的函数签名:

void foo<T>()

您可以添加一个泛型约束以仅允许值类型:

void foo<T>() where T : struct

注意,这不仅允许 T 的基本类型,而且允许任何值类型。

我只是在寻找类似的解决方案时发现了这个问题,并且认为您可能对使用 System.TypeCodeSystem.Convert的以下方法感兴趣。

很容易序列化映射到除 System.TypeCode.Object以外的 System.TypeCode的任何类型,因此您可以:

object PropertyValue = ...
if(Convert.GetTypeCode(PropertyValue) != TypeCode.Object)
{
string StringValue = Convert.ToString(PropertyValue);
...
}

这种方法的优点是您不必命名所有其他可接受的非基元类型。您还可以稍微修改上面的代码,以处理实现 IConvertable 的任何类型。

我们在 ORM 中是这样做的:

Type t;
bool isPrimitiveType = t.IsPrimitive || t.IsValueType || (t == typeof(string));

我知道使用 IsValueType不是最好的选择(您可以拥有自己的非常复杂的结构) ,但是它在99% 的情况下都可以工作(包括 Nullables)。

这是我在我的图书馆。欢迎评论。

我首先检查 IsValueType,因为它处理大多数类型,然后检查 String,因为它是第二常见的类型。我想不出一个不是值类型的基元,所以我不知道 if 的那条腿是否被打中。

  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

然后我可以这样使用它:

  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

我是这么做的。

   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;
}
}

2020年最新情况

从@Xav987的回答中派生出来的,它执行得更好,代码也更少。

    static readonly ConcurrentDictionary<Type, bool> IsSimpleTypeCache = new ConcurrentDictionary<System.Type, bool>();


public static bool IsSimpleType(Type type)
{
return IsSimpleTypeCache.GetOrAdd(type, t =>
type.IsPrimitive ||
type.IsEnum ||
type == typeof(string) ||
type == typeof(decimal) ||
type == typeof(DateTime) ||
type == typeof(DateTimeOffset) ||
type == typeof(TimeSpan) ||
type == typeof(Guid) ||
IsNullableSimpleType(type));


static bool IsNullableSimpleType(Type t)
{
var underlyingType = Nullable.GetUnderlyingType(t);
return underlyingType != null && IsSimpleType(underlyingType);
}
}


为了将类型导出到 XML,我需要序列化它们。为此,我遍历该对象并选择基元、枚举、值类型或可序列化的字段。这是我提问的结果:

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});

我使用 LINQ 来迭代这些类型,然后获取它们的名称和值以存储在一个符号表中。关键在于我选择的“ where”子句。我选择了基元类型、枚举类型、值类型和可序列化类型。这允许字符串和 DateTime 对象按照我的预期进行。

干杯!

还有一个很好的可能性:

private static bool IsPrimitiveType(Type type)
{
return (type == typeof(object) || Type.GetTypeCode(type) != TypeCode.Object);
}

我只是想分享我的解决方案,也许对任何人都有用。

public static bool IsPrimitiveType(Type fieldType)
{
return fieldType.IsPrimitive || fieldType.Namespace.Equals("System");
}
public static bool IsPrimitiveType(object myObject)
{
var myType = myObject.GetType();
return myType.IsPrimitive || myType.Namespace == null ||  myType.Namespace.Equals("System");
}

不要忘记检查 NULL 名称空间,因为匿名对象没有指定名称空间

通过@Ronnie Overby response 和@jonathanconway 注释,我编写了这个适用于 Nullable 并排除用户结构的方法。

public static bool IsSimpleType(Type type)
{
return
type.IsPrimitive ||
new Type[] {
typeof(string),
typeof(decimal),
typeof(DateTime),
typeof(DateTimeOffset),
typeof(TimeSpan),
typeof(Guid)
}.Contains(type) ||
type.IsEnum ||
Convert.GetTypeCode(type) != TypeCode.Object ||
(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) && IsSimpleType(type.GetGenericArguments()[0]))
;
}

使用以下 TestCase:

struct TestStruct
{
public string Prop1;
public int Prop2;
}


class TestClass1
{
public string Prop1;
public int Prop2;
}


enum TestEnum { TheValue }


[Test]
public void Test1()
{
Assert.IsTrue(IsSimpleType(typeof(TestEnum)));
Assert.IsTrue(IsSimpleType(typeof(string)));
Assert.IsTrue(IsSimpleType(typeof(char)));
Assert.IsTrue(IsSimpleType(typeof(Guid)));


Assert.IsTrue(IsSimpleType(typeof(bool)));
Assert.IsTrue(IsSimpleType(typeof(byte)));
Assert.IsTrue(IsSimpleType(typeof(short)));
Assert.IsTrue(IsSimpleType(typeof(int)));
Assert.IsTrue(IsSimpleType(typeof(long)));
Assert.IsTrue(IsSimpleType(typeof(float)));
Assert.IsTrue(IsSimpleType(typeof(double)));
Assert.IsTrue(IsSimpleType(typeof(decimal)));


Assert.IsTrue(IsSimpleType(typeof(sbyte)));
Assert.IsTrue(IsSimpleType(typeof(ushort)));
Assert.IsTrue(IsSimpleType(typeof(uint)));
Assert.IsTrue(IsSimpleType(typeof(ulong)));


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(TestEnum?)));
Assert.IsTrue(IsSimpleType(typeof(char?)));
Assert.IsTrue(IsSimpleType(typeof(Guid?)));


Assert.IsTrue(IsSimpleType(typeof(bool?)));
Assert.IsTrue(IsSimpleType(typeof(byte?)));
Assert.IsTrue(IsSimpleType(typeof(short?)));
Assert.IsTrue(IsSimpleType(typeof(int?)));
Assert.IsTrue(IsSimpleType(typeof(long?)));
Assert.IsTrue(IsSimpleType(typeof(float?)));
Assert.IsTrue(IsSimpleType(typeof(double?)));
Assert.IsTrue(IsSimpleType(typeof(decimal?)));


Assert.IsTrue(IsSimpleType(typeof(sbyte?)));
Assert.IsTrue(IsSimpleType(typeof(ushort?)));
Assert.IsTrue(IsSimpleType(typeof(uint?)));
Assert.IsTrue(IsSimpleType(typeof(ulong?)));


Assert.IsTrue(IsSimpleType(typeof(DateTime?)));
Assert.IsTrue(IsSimpleType(typeof(DateTimeOffset?)));
Assert.IsTrue(IsSimpleType(typeof(TimeSpan?)));


Assert.IsFalse(IsSimpleType(typeof(TestStruct?)));
}

这是另一个可行的选择。

public static bool CanDirectlyCompare(Type type)
{
return typeof(IComparable).IsAssignableFrom(type) || type.IsPrimitive || type.IsValueType;
}

仅适用于基本类型 String、 Decimal、 DateTime、 DateTimeOffset、 TimeSpan 和 Guid 的扩展方法。< br > 如果希望包含泛型、结构和枚举,可以在 OR 中添加 type.IsValueType。

    private static readonly Type[] PrimitiveLikeTypes = new[]
{
typeof(string),
typeof(decimal),
typeof(DateTime),
typeof(DateTimeOffset),
typeof(TimeSpan),
typeof(Guid)
};


/// <summary>
/// Determine whether a type is simple (Primitive, String, Decimal, DateTime, etc)
/// or complex (i.e. structs, Enums, custom class with public properties and methods).
/// Returns false for structs and Enums
/// </summary>
/// <param name="type">System.Type</param>
/// <returns> boolean value indicating whether the type is simple or not</returns>
public static bool IsSimpleType(this Type type)
{
return type.IsPrimitive || PrimitiveLikeTypes.Contains(type);
}