如何测试类型是否为原始


162

我有一段代码将类型序列化为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。我希望它忽略其他所有内容,例如列表和其他自定义类型。

谁能建议我该怎么做?还是我需要在某个地方指定要允许的类型,然后打开属性的类型以查看是否允许?有点杂乱,所以如果我有一个更简洁的方法,那就太好了。


12
System.String不是原始类型。
Slaks

3
更好的方法是根本不使用泛型。如果您支持少量类型作为合法参数类型,那么只需重载那么多。如果支持实现ISerializable的任何类型,则编写一个采用ISerializable的非泛型方法。使用的东西实际上是仿制药仿制 ; 如果类型确实很重要,则可能不是通用的。
埃里克·利珀特

@Eric:谢谢,我也想知道您是否可以对数字使用相同的条件?例如,编写支持所有数字类型(例如,平均值,总和等)的数学函数。应使用泛型或重载实现它们吗?实施是否相同是否重要?因为对于任何数字类型,Average,Sum的运算几乎相同,对吗?
Joan Venge 2010年

1
@Joan:能够在受约束实现各种运算符的类型上编写通用算术方法是一个经常需要的功能,但是它需要CLR支持,并且异常复杂。我们正在考虑将其用于语言的未来版本,但没有任何希望。
埃里克·利珀特

Answers:


182

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

编辑1: 添加了示例代码

这是一个示例代码:

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

编辑2:作为@SLaks注释,也许您也想将其他类型视为原语。我认为您必须将这些变化一个接一个地添加。

编辑3: IsPrimitive =(布尔值,字节,SByte,Int16,UInt16,Int32,UInt32,Int64,UInt64,IntPtr,UIntPtr,Char,Double和Single),要检查的花药基本类型(t == typeof(DateTime ))


12
也许DateTimeTimeSpanDateTimeOffset
Slaks

嗯...是的,你是对的。我认为我们将不得不添加更多可能性
哈维尔2010年

2
您需要使用逻辑或(||),而不是按位或(|)。
Slaks

42
这是我编写的一种扩展方法,可以方便地运行@Javier和Michael Petito的答案中所述的测试:gist.github.com/3330614
乔纳森(Jonathan)

5
您可以使用属性Type.IsValueType并仅添加字符串检查。
Matteo Migliore

57

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

这是很容易序列化映射到任何类型System.TypeCode以外System.TypeCode.Object,所以你可以这样做:

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

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


2
太好了,我必须Guid出于自己的目的手动添加(作为我定义中的基本体)。
埃里克·飞利浦

56

我们在ORM中这样做:

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

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


6
如果使用IsValueType,为什么需要IsPrimitive?并不是所有的原始值类型?
JoelFan 2014年

5
@JoelFan十进制类型的IsPrimitive为false,但IsValueType为true
xhafan 2014年

3
@xhafan:您回答错误的问题。decimal在这方面,所有结构都类似。但是,是否有IsPrimitive返回trueIsValueType返回的类型false?如果没有这种类型,则t.IsPrimitive不需要测试。
2015年

6
@Lii,您是对的,每个原始类型都已IsValueType设置为true,因此IsPrimitive不需要进行检查。干杯!
xhafan

1
@Veverke他们没有。您可以具有非原始值类型,在这种情况下,属性具有不同的值。
Michael Petito

38

从@Ronnie Overby响应和@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?)));
}

1
这是一个很好的方法,但是Enum不支持使用enum MyEnum { EnumValue }并使用进行测试MyEnum。@Jonathan也正在使用type.IsValueType。这样,就Enums可以正确检测到Structs。因此,请注意您想要什么原语。
Apfelkuacha

1
@Apfelkuacha:你完全正确。但是type.IsValueType,为什么不使用,而不是使用type.IsEnum
Xav987

你是完全正确的。type.IsEnum也有可能。我建议对您的帖子进行编辑:)
Apfelkuacha

16

这是我的方法。

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

@RonnieOverby。IsAssignableFrom在测试中使用而不是包含有什么特别的原因吗?
约翰尼

6

也有可能:

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

的每个实例Type都有一个称为IsPrimitive的属性。您应该改用它。
Renan

3
无论是String也不Decimal是原语。
k3flo

这对我有用,但是我将其重命名为IsClrType,以使其与现有的.IsPrimitive类型类不混淆
KnarfaLingus 2015年

1
例如,这不会选择Guid或TimeSpan。
斯坦尼斯拉夫,

3

假设您具有如下功能签名:

void foo<T>() 

您可以添加通用约束以仅允许值类型:

void foo<T>() where T : struct

注意,这不仅允许T的原始类型,还允许任何值类型。


2

为了将类型导出到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对象通过我所期望的。

干杯!


1

这就是我图书馆里的东西。欢迎发表评论。

我先检查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

0

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

public static bool IsPrimitiveType(Type fieldType)
{
   return fieldType.IsPrimitive || fieldType.Namespace.Equals("System");
}

5
IsPrimitiveType(typeof(System.AccessViolationException)) == true
罗尼·奥弗比

2
namespace System { class MyNonPrimitiveType { } }
罗尼·奥弗比

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

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


0

这是另一个可行的选择。

public static bool CanDirectlyCompare(Type type)
{
    return typeof(IComparable).IsAssignableFrom(type) || type.IsPrimitive || type.IsValueType;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.