タイプがプリミティブかどうかをテストする方法


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 Lippert

@エリック:ありがとう、数値でも同じ基準を使用できるかどうか疑問に思っていますか?たとえば、Average、Sumなど、すべての数値型をサポートする数学関数を作成するには、これらをジェネリックまたはオーバーロードを使用して実装する必要がありますか?実装が同じかどうかは重要ですか?これは、Average、Sumの数値型の操作とほとんど同じなので、そうですか?
Joan Venge 2010年

1
@Joan:さまざまな演算子を実装するように制約された型で一般的な算術メソッドを記述できることは、頻繁に要求される機能ですが、CLRサポートが必要であり、驚くほど複雑です。この言語の将来のバージョンで検討していますが、約束はありません。
Eric Lippert、2010年

回答:


182

プロパティを使用Type.IsPrimitiveできますが、プリミティブであると考えることができるいくつかのタイプがあるので注意してください。たとえばDecimal、およびはそうではありませんString

編集1: サンプルコードを追加

これがサンプルコードです:

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

編集2:@SLaksコメントとして、おそらくプリミティブとして扱いたい他のタイプもあります。このバリエーションを1つずつ追加する必要があると思います。

編集3: IsPrimitive =(ブール、バイト、SByte、Int16、UInt16、Int32、UInt32、Int64、UInt64、IntPtr、UIntPtr、Char、Double、およびSingle)、チェックするAnther Primitive-Likeタイプ(t == typeof(DateTime ))


12
そしておそらくDateTimeTimeSpanDateTimeOffset
SLaks '14 / 03/10

うーん...はい、そうです。いくつかの可能性を追加する必要があると思います
Javier

2
||ビット単位のor(|)ではなく、論理or()を使用する必要があります。
SLaks '14 / 03/14

42
@JavierとMichael Petitoの回答で説明されているテストを簡単に実行するために私が作成した拡張メソッドは次のとおりです:gist.github.com/3330614
ジョナサン

5
Type.IsValueTypeプロパティを使用して、文字列のチェックのみを追加できます。
Matteo Migliore 2013年

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 10進数型はIsPrimitive falseですが、IsValueTypeはtrue
xhafan

3
@xhafan:あなたは間違った質問に答えます。すべての構造体はdecimalその点で似ています。しかし、IsPrimitive返されるtrueIsValueType返されるタイプはありますfalseか?そのようなタイプがない場合、t.IsPrimitiveテストは不要です。
Lii

6
@Lii正解です。すべてのプリミティブ型がIsValueTypetrueに設定されているため、チェックするIsPrimitive必要はありません。乾杯!
xhafan 2015年

1
@Veverke彼らはしません。非プリミティブ値タイプを使用できます。その場合、プロパティは異なる値になります。
Michael Petito 2015

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包含の代わりにテストで使用する特定の理由はありますか?
ジョニー2018年

6

また、良い可能性:

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

のすべてのインスタンスにTypeは、IsPrimitiveというプロパティがあります。代わりにそれを使用する必要があります。
レナン2013年

3
どちらStringDecimalプリミティブではありません。
k3flo 2013年

これは私にとってはうまくいきますが、Typeクラスの既存の.IsPrimitiveとその意味を混同しないように、IsClrTypeに名前を変更しました
KnarfaLingus

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が2番目に一般的であるためです。私は値型ではないプリミティブを考えることができないので、そのレッグがヒットするかどうかはわかりません。

  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(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;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.