유형이 원시인지 테스트하는 방법


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

나는 단지 기본 유형과 같은이 작업을 수행 할 제외하고 이것은 좋은 작품 int, double, bool원시적 아니지만처럼 쉽게 직렬화 할 수있는 등, 다른 종류 string. Lists 및 기타 사용자 정의 유형과 같은 다른 모든 것을 무시하고 싶습니다.

아무도 내가 어떻게하는지 제안 할 수 있습니까? 또는 어딘가에 허용하려는 유형을 지정하고 속성 유형을 켜서 허용되는지 확인해야합니까? 조금 지저분하기 때문에 더 깔끔한 방법이 있다면 좋을 것입니다.


12
System.String기본 유형이 아닙니다.
SLaks

3
더 좋은 방법은 제네릭을 전혀 사용하지 않는 것입니다. 적법한 매개 변수 유형으로 적은 수의 유형을 지원하는 경우 단순히 그 많은 과부하를가집니다. ISerializable을 구현하는 모든 유형을 지원하는 경우 ISerializable을 취하는 제네릭이 아닌 메서드를 작성하십시오. 실제로 일반적인 것들에는 제네릭을 사용하십시오 . 유형이 실제로 중요하면 일반적이지 않을 것입니다.
Eric Lippert

@ 에릭 : 감사합니다. 숫자와 동일한 기준을 사용할 수 있는지 궁금합니다. 예를 들어, 모든 숫자 유형 (예 : Average, Sum 등)을 지원하는 수학 함수를 작성하려면 Generic 또는 과부하를 사용하여 구현해야합니까? 구현이 동일한 지 여부가 중요합니까? 그것은 Average에 대해서도 거의 같은 연산이기 때문에 어떤 숫자 유형에 대해서도 Sum입니까?
Joan Venge

1
@Joan : 다양한 연산자를 구현하도록 제한된 유형에 대해 일반 산술 메소드를 작성할 수있는 것은 자주 요청되는 기능이지만 CLR 지원이 필요하며 놀랍도록 복잡합니다. 우리는 언어의 미래 버전을 고려하고 있지만 약속은 없습니다.
Eric Lippert

답변:


184

당신은 속성을 사용할 수 있습니다 Type.IsPrimitive,하지만 우리는 프리미티브 것을 생각할 수있는 몇 가지 종류가 있기 때문에주의 하시고, 그러나 그들은 예를 들어, 됐소 Decimal하고 String.

편집 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
그리고 아마도 DateTime, TimeSpanDateTimeOffset.
SLaks

음 ... 네 맞아요. 우리는 더 많은 가능성을 추가해야한다고 생각합니다
Javier

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합니다. 내 목적을 위해 수동으로 추가해야 했습니다 (정의의 기본 요소).
Erik Philips

56

우리는 ORM에서 다음과 같이합니다.

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

나는 사용하는 IsValueType것이 최선의 선택이 아니라는 것을 알고 있지만 (너무 복잡한 구조체를 가질 수는 있지만) 99 %의 경우 작동합니다 (Nullables 포함).


6
IsValueType을 사용하는 경우 왜 IsPrimitive가 필요합니까? 모든 프리미티브 값 유형이 아닙니까?
JoelFan

5
@JoelFan 10 진수 유형의 IsPrimitive는 false이지만 IsValueType true
xhafan

3
@ xhafan : 당신은 잘못된 질문에 대답합니다. 모든 구조체는 그런 decimal점에서 비슷 합니다. 그러나 IsPrimitive반환 true하지만 IsValueType반환 하는 유형이 false있습니까? 이러한 유형이 없으면 t.IsPrimitive테스트가 필요하지 않습니다.
Lii

6
@Lii 맞습니다. 모든 기본 유형이 IsValueTypetrue로 설정되었으므로 검사 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포함하지 않고 테스트에 사용하는 특별한 이유 가 있습니까?
johnny 5

6

또한 좋은 가능성 :

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

의 모든 인스턴스 Type에는 IsPrimitive 라는 속성이 있습니다 . 대신 사용해야합니다.
Renan

3
프리미티브 도 String아닙니다 Decimal.
k3flo 2016 년

나를 위해이 작품,하지만 난 Type 클래스의 기존 .IsPrimitive와 그 의미를 혼동하지 않도록 IsClrType로 변경
KnarfaLingus

1
예를 들어 Guid 또는 TimeSpan을 선택하지 않습니다.
Stanislav

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
Ronnie

2
namespace System { class MyNonPrimitiveType { } }
Ronnie

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.