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

C# 如何测试类型是否为基元,c#,reflection,primitive-types,C#,Reflection,Primitive Types,我有一段代码将类型序列化为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);

我有一段代码将类型序列化为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);
}
Type t=typeof(t);//我作为一个参数传入,其中myObj是类型T
tagBuilder.Attributes.Add(“class”,t.Name);
foreach(t.GetProperties()中的PropertyInfo属性)
{
对象propValue=prop.GetValue(myObj,null);
string stringValue=propValue!=null?propValue.ToString():string.Empty;
tagBuilder.Attributes.Add(prop.Name,stringValue);
}
这非常有效,但我希望它只对基本类型执行此操作,如
int
double
bool
等,以及其他非基本类型但可以轻松序列化的类型,如
string
。我希望它忽略其他所有内容,如列表和其他自定义类型


有人能建议我怎么做吗?或者我需要在某个地方指定要允许的类型,然后打开属性的类型以查看是否允许?这有点乱,所以如果我有一个更整洁的方法就好了。

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

编辑1:添加示例代码

下面是一个示例代码:

if (t.IsPrimitive || t == typeof(Decimal) || t == typeof(String) || ... )
{
    // Is Primitive, or Decimal, or String
}
编辑2:作为注释,您可能也希望将其他类型视为基本体。我认为你必须一个接一个地添加这些变体

编辑3:IsPrimitive=(布尔、字节、SByte、Int16、UInt16、Int32、UInt32、UInt32、Int64、UInt64、UInt64、UInt64、IntPtr、UIntPtr、Char、Double和Single),
另一个要检查的类似原语的类型(t==typeof(DateTime))

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

void foo<T>() 
void foo()
可以添加泛型约束以仅允许值类型:

void foo<T>() where T : struct
void foo(),其中T:struct

请注意,这不仅允许T的基元类型,还允许任何值类型。

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

可以轻松序列化映射到
System.TypeCode
的任何类型,而不是
System.TypeCode.Object
,因此您可以执行以下操作:

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

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

我们在ORM中这样做:

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

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

这就是我的库中的内容。欢迎评论

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

公共共享函数IsPersistable(类型为System.Type)为布尔值
带类型信息。参考类型(类型)
Return.IsValueType OrElse Type=GetType(字符串)OrElse.IsPrimitive
以
端函数
公共共享函数可作为布尔值为Null(ByVal类型为System.Type)
Return(Type.IsGenericType)和also(Type.GetGenericTypeDefinition()是GetType(null可为(Of)))
端函数
公共共享函数underyingType(ByVal类型作为System.Type)作为System.Type
如果IsNullable(类型),则
返回Nullable.GetUnderlyingType(类型)
其他的
返回类型
如果结束
端函数
然后我可以这样使用它:

void foo<T>() 
公共共享函数PersistableProperties(项作为System.Type)作为IEnumerable(属于System.Reflection.PropertyInfo)
从Item.GetProperties()中的PropertyInfo返回
其中PropertyInfo.CanWrite和also(IsPersistable(PropertyInfo.PropertyType))
选择PropertyInfo
端函数
我是这样做的

   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;
       }
   }
静态类基本类型
{
公共静态只读类型[]列表;
静态基本类型()
{
变量类型=新[]
{
类型(枚举),
类型(字符串),
类型(字符),
类型(Guid),
类型(布尔),
类型(字节),
类型(Int16),
类型(Int32),
类型(Int64),
类型(单个),
类型(双),
类型(十进制),
类型(SByte),
类型(UInt16),
类型(UInt32),
类型(UInt64),
类型(日期时间),
类型(日期时间偏移量),
类型(时间跨度),
};
var nullTypes=来自类型中的t
其中t.IsValueType
选择typeof(可为空)。MakeGenericType(t);
List=types.Concat(nullTypes.ToArray();
}
公共静态布尔测试(类型)
{
if(List.Any(x=>x.IsAssignableFrom(type)))
返回true;
var nut=Nullable.getUnderlineType(类型);
返回螺母!=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);
        }
    }

静态只读ConcurrentDictionary IsSimpleTypeCache=new ConcurrentDictionary();
公共静态布尔IsSimpleType(类型)
{
返回IsSimpleTypeCache.GetOrAdd(类型,t=>
type.IsPrimitive||
类型。
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");
}
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]))
        ;
}
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;
}