객체가 nullable인지 확인하는 방법?


202

주어진 객체가 nullable인지 확인하는 방법은 다음과 같습니다.

bool IsNullableValueType(object o)
{
    ...
}

편집 : nullable 값 형식을 찾고 있습니다. 심판 유형을 염두에 두지 않았습니다.

//Note: This is just a sample. The code has been simplified 
//to fit in a post.

public class BoolContainer
{
    bool? myBool = true;
}

var bc = new BoolContainer();

const BindingFlags bindingFlags = BindingFlags.Public
                        | BindingFlags.NonPublic
                        | BindingFlags.Instance
                        ;


object obj;
object o = (object)bc;

foreach (var fieldInfo in o.GetType().GetFields(bindingFlags))
{
    obj = (object)fieldInfo.GetValue(o);
}

obj는 이제 값이 같은 bool( System.Boolean) 유형의 객체를 참조 합니다 true. 내가 정말로 원하는 것은 유형의 객체였습니다Nullable<bool>

이제 해결 방법으로 o가 nullable인지 확인하고 obj 주위에 nullable 래퍼를 만들기로 결정했습니다.


코드에 문자열이 nullable로 포함되어야합니까? 제네릭이 아닌 ValueType이며 nullable로 나타납니다. 아니면 그들은 ValueType이 아닌가?
TamusJRoyce

문자열이 ValueType이 아닙니다. 참조 유형입니다.
Suncat2000

이것은 정말 좋은 질문입니다! 'Type.IsNullableType ()'은 실제로 유형이 'Nullable <T>'인지 확인하기 때문에 일종의 속임수입니다. 실제로 null을 허용 할 수있는 형식을 확인하려는 경우 예상 결과를 반환하지 않았습니다. value (예를 들어 a.IsNullableType ()과 함께 사용하려고했습니다. 여기서 'a'는 런타임에 결정된 'typeof (string)'입니다)
ErrCode

답이 fieldInfo.FieldType에 있습니다. FieldType이 제네릭이고 제네릭 형식이 Nullable <> 형식인지 확인하십시오. (예 : if (FieldType.IsGenericType && FieldType.GetGenericTypeDefinition () == typeof (Nullable <>))). obj.GetType ()을 얻으려고 시도하지 마십시오. UndelyingSystemType의 Nullable <T> 변수 T (Nullable <Boolean> 대신 Boolean 유형의 경우)는 권투 문제입니다.
SoLaR

답변:


271

널 입력 가능 유형 Nullable<T>과 참조 유형의 두 가지 유형이 있습니다.

Jon은 상자에 넣으면 입력하기가 어렵다는 것을 수정했지만 generics를 사용하면 다음과 같이 할 수 있습니다. 이것은 실제로 type 테스트 T중이지만 obj일반 유형 유추에 대해서만 순수하게 매개 변수를 사용하면 쉽게 호출 할 수 있습니다 obj. 그러나 매개 변수 없이 거의 동일하게 작동합니다 .

static bool IsNullable<T>(T obj)
{
    if (obj == null) return true; // obvious
    Type type = typeof(T);
    if (!type.IsValueType) return true; // ref-type
    if (Nullable.GetUnderlyingType(type) != null) return true; // Nullable<T>
    return false; // value-type
}

그러나 객체 변수에 이미 값을 상자에 넣으면 제대로 작동하지 않습니다.

Microsoft 설명서 : https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/nullable-types/how-to-identify-a-nullable-type


7
마지막 줄은 어떻게 든 T로 똑바로 boxing하는 대신 boxed Nullable <T>을 얻는 경우에만 유효합니다. 기억하는 것에서 달성하는 것은 가능하지만 까다 롭습니다.
Jon Skeet

이 코드는 박스형 Nullable <T>을 얻었 기 때문에가 아니라 일반 WPF 변환기 기본 클래스를 작성하고 일부 속성이 nullable이므로 Nullable.GetUnderlyingType을 사용하여 해당 사례를 감지하고 Activator.CreateInstance를 만들었습니다. 박스형 널 입력 가능 (Convert.ChangeType은 널 입력 가능 btw를 처리하지 않음)
Qwertie

1
@Abel 그가 참조 유형을 고려하지 않았다는 것을 명확히하기 위해 그의 편집을 다시 의미한다면, 내 대답이 그 편집보다 우선 했다고 생각합니다 . 독자는 자신의 필요에 따라 거기에서 스스로 결정을 내릴 수 있다고 생각합니다 (확인 : 14:42에 추가 된 그의 의견 참조 유형; 내 대답은 모두 <= 14:34)
Marc Gravell

1
obj = 1 일 때 (obj == null) 예외가 발생합니까?
제나라 팬

3
@JustinMorgan 경우 T제약 일반적인 매개 변수 T : struct, 다음 T으로 허용되지 않습니다 Nullable<>당신이 경우에 확인이 필요 없습니다, 그래서! 형식 Nullable<>이 구조체 라는 것을 알고 있지만 C #에서는 제약 조건이 where T : structnullable 값 형식을 제외시킵니다. 스펙은 "값 유형으로 분류되지만 널 입력 가능 유형 (§4.1.10)은 값 유형 제한 조건을 만족하지 않습니다."
Jeppe Stig Nielsen

46

메소드 오버로드를 사용하는 매우 간단한 솔루션이 있습니다

http://deanchalk.com/is-it-nullable/

발췌 :

public static class ValueTypeHelper
{
    public static bool IsNullable<T>(T t) { return false; }
    public static bool IsNullable<T>(T? t) where T : struct { return true; }
}

그때

static void Main(string[] args)
{
    int a = 123;
    int? b = null;
    object c = new object();
    object d = null;
    int? e = 456;
    var f = (int?)789;
    bool result1 = ValueTypeHelper.IsNullable(a); // false
    bool result2 = ValueTypeHelper.IsNullable(b); // true
    bool result3 = ValueTypeHelper.IsNullable(c); // false
    bool result4 = ValueTypeHelper.IsNullable(d); // false
    bool result5 = ValueTypeHelper.IsNullable(e); // true
    bool result6 = ValueTypeHelper.IsNullable(f); // true

7
테스트 케이스를 추가하기 위해 하나 더합니다. 다른 모든 답변을 확인하기 위해 해당 테스트 사례를 사용했습니다. 더 많은 사람들 이이 여분의 비트를 가야합니다.
Marty Neal

4
가치있는 것은 VB.NET에서 작동하지 않습니다. 반환 되는 모든 상황에서 " 이 인수에 가장 적합한 액세스 가능한 'IsNullable'이 없기 때문에 과부하 해결에 실패했습니다 "라는 컴파일러 오류가 발생 True합니다.
ckittel

1
나는이 솔루션을 정말로 좋아합니다 .VB가 처리 할 수없는 것은 부끄러운 일입니다. ValueType을 사용하여 작업을 시도했지만 공유 메소드 또는 확장으로 호출되었는지 여부에 따라 사용할 과부하에 대해 VB 컴파일러가 일치하지 않아 문제가 발생했습니다. 이상한 것처럼 보일 수도 있습니다 : stackoverflow.com/ 질문 / 12319591 /…
제임스 닫기

22
컴파일 타임 유형을 확인하고 있지만 컴파일 타임 유형이 nullable ( System.Nullable<>) 이면 이미 인텔리전스에서 분명 합니다. 당신이 말 object g = e;을하면 ValueTypeHelper.IsNullable(g), 무엇을 얻을 것으로 예상됩니까?
Jeppe Stig Nielsen

18
방금 확인했습니다. Jeppe가 말했듯 이 이것은 작동하지 않습니다 . 변수가 객체로 캐스트되면 항상 false를 반환합니다. 따라서 런타임시 알 수없는 객체의 유형을 확인할 수 없습니다. 이것이 작동하는 유일한 시간은 유형이 컴파일 타임에 고정 된 경우이며,이 경우 런타임 검사가 전혀 필요하지 않습니다.
HugoRune

30

"유형이 nullable인지 확인하는 방법은 무엇입니까?" 실제로 "유형이 있는지 어떻게 확인하는 것입니다 Nullable<>?", 일반화 할 수있는 "유형이 일부 제네릭 형식의 구성 형식 인 경우 확인하는 방법?"는 질문에 대답뿐만 아니라 그래서 "인가 Nullable<int>Nullable<>?" 또한 "있는List<int>List<> ?".

제공된 솔루션의 대부분은이 방법을 사용하며 Nullable.GetUnderlyingType()이는의 경우에만 작동합니다 Nullable<>. 나는 일반적인 유형에서 작동하는 일반적인 반사 솔루션을 보지 못했기 때문에이 질문이 이미 오래 전에 답변되었지만 여기에 후손을 위해 추가하기로 결정했습니다.

유형이 Nullable<>리플렉션 을 사용 하는 형태인지 확인하려면 먼저 생성 된 제네릭 유형 (예 Nullable<int>:)을 제네릭 유형 정의 로 변환해야합니다 Nullable<>. 클래스 의 GetGenericTypeDefinition()메소드를 사용하여이를 수행 할 수 있습니다 Type. 그런 다음 결과 유형을 다음과 비교할 수 있습니다 Nullable<>.

Type typeToTest = typeof(Nullable<int>);
bool isNullable = typeToTest.GetGenericTypeDefinition() == typeof(Nullable<>);
// isNullable == true

모든 일반 유형에 동일하게 적용 할 수 있습니다.

Type typeToTest = typeof(List<int>);
bool isList = typeToTest.GetGenericTypeDefinition() == typeof(List<>);
// isList == true

여러 유형이 동일하게 보일 수 있지만 유형 인수의 수가 다르면 완전히 다른 유형임을 의미합니다.

Type typeToTest = typeof(Action<DateTime, float>);
bool isAction1 = typeToTest.GetGenericTypeDefinition() == typeof(Action<>);
bool isAction2 = typeToTest.GetGenericTypeDefinition() == typeof(Action<,>);
bool isAction3 = typeToTest.GetGenericTypeDefinition() == typeof(Action<,,>);
// isAction1 == false
// isAction2 == true
// isAction3 == false

Type객체는 유형별로 한 번 인스턴스화 되므로 객체 간의 참조 동등성을 확인할 수 있습니다. 따라서 두 객체가 동일한 제네릭 형식 정의인지 확인하려면 다음과 같이 쓸 수 있습니다.

var listOfInts = new List<int>();
var listOfStrings = new List<string>();

bool areSameGenericType =
    listOfInts.GetType().GetGenericTypeDefinition() ==
    listOfStrings.GetType().GetGenericTypeDefinition();
// areSameGenericType == true

객체가 null이 아닌 nullable인지 확인 Type하려면 위의 기술을 Marc Gravell의 솔루션과 함께 사용하여 간단한 방법을 만들 수 있습니다.

static bool IsNullable<T>(T obj)
{
    if (!typeof(T).IsGenericType)
        return false;

    return typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>);
}

@ AllonGuralnek 내 대답에는 간단한 버전이 있습니다. 나는 그것을 편집으로 만들고 싶었고 내 명성이 당신의 수준이 아니기 때문에 대답에 내 이름이 없으면 편집 될 것입니다. 아니. 이상한 세상, 어떤 사람들은 정의를 얻지 못합니다 :).
ipavlu

@ipavlu : 버전이 단순화되지 않았으며 실제로는 더 복잡합니다. 결과를 캐시했기 때문에 최적화 된 것 같습니다. 이해하기가 더 어렵습니다.
Allon Guralnek

@ AllonGuralnek 정적 제네릭 클래스와 정적 한 번 초기화 필드는 복잡합니까? 사랑하는 하나님, 나는 끔찍한 범죄를 저질렀습니다 :).
ipavlu

@ipavku : 네, "객체가 널 입력 가능 여부를 확인하는 방법"이라는 질문과는 관련이 없기 때문입니다. 나는 그것을 간단하고 요점으로 유지하려고 노력하며 필요하지 않고 관련이없는 개념을 도입하는 것을 피합니다.
Allon Guralnek

1
@ nawfal : 내가 당신을 올바르게 이해했다면, 당신 Nullable.GetUnderlyingType()은 이미 프레임 워크가 제공 한 존재에 직면하여 구현을 추구합니다 . 왜 프레임 워크에서 메소드를 사용하지 않습니까? 글쎄, 당신은해야합니다. 더 명확하고 간결하며 더 나은 테스트를 거쳤습니다. 그러나 내 게시물에서 리플렉션을 사용하여 원하는 정보를 얻는 방법을 가르치려고하여 typeof(Nullable<>)다른 유형 으로 대체 하여 다른 유형으로 정보를 적용 할 수 있습니다 . GetUnderlyingType()(원본 또는 디 컴파일 된) 소스를 살펴보면 내 코드와 매우 유사하다는 것을 알 수 있습니다.
Allon Guralnek

30

이것은 나를 위해 작동하며 간단 해 보입니다.

static bool IsNullable<T>(T obj)
{
    return default(T) == null;
}

값 유형의 경우 :

static bool IsNullableValueType<T>(T obj)
{
    return default(T) == null && typeof(T).BaseType != null && "ValueType".Equals(typeof(T).BaseType.Name);
}

7
가치가있는 것은 Microsoft가 사용
canton7

1
니스 ... 나중에 올린 가장 큰 원인이 아닌가? 나는 가장 혼란스러운 답을 찾았습니다.
Vincent Buscarello

1
이것이 최고의 답변이어야합니다. 다른 방법을 시도한 후 며칠 동안이 솔루션을 무작위로 생각하고 시도했으며 완벽하게 작동하는 것 같습니다 (최고의 답변과 비교)
user3163495

2
이것은 인스턴스를 NULL로 설정할 수 있는지 확인하는 훌륭한 솔루션이지만 일반 객체를 포함하여 null로 설정할 수있는 모든 항목에 대해 true를 반환 합니다. 원래 질문은 특히 Nullable ValueTypes를 감지하기를 원했다는 것을 인식하는 것이 중요합니다.
JamesHoux

20

글쎄, 당신은 사용할 수 있습니다 :

return !(o is ValueType);

...하지만 객체 자체는 nullable이 아니거나 유형 이 아닙니다 . 이것을 어떻게 사용할 계획 이었습니까?


2
이것은 나를 조금 던져 버렸다. 예를 들어 int? i = 5; typeof (i)는 Nullable <Int32> 대신 System.Int32를 반환합니다.-typeof (int?)는 Nullable <Int32>를 반환합니다.이 항목에 대한 명확성을 얻을 수있는 곳은 어디입니까?
Gishu

2
typeof (i)는 컴파일러 오류를 발생시킵니다-변수와 함께 typeof를 사용할 수 없습니다. 실제로 무엇을 했습니까?
Jon Skeet

15
i.GetType ()은 먼저 Object에 상자를 만들고 상자에 넣을 수있는 nullable 형식은 없습니다. Nullable <int>는 상자에 null 참조 또는 상자에 삽입 된 int를 가져옵니다.
Jon Skeet

이 방법은 Nullable.GetUnderlyingType (type)! = null보다 낫습니다.
Kiquenet

@Kiquenet : 우리는하지 않습니다 여기 유형 - 단지 값입니다.
Jon Skeet

11

내가 알아낼 수있는 가장 간단한 방법은 다음과 같습니다.

public bool IsNullable(object obj)
{
    Type t = obj.GetType();
    return t.IsGenericType 
        && t.GetGenericTypeDefinition() == typeof(Nullable<>);
}

+1. 박스형 널 입력 유형에 대한 탁월한 솔루션입니다. 나는 이것을 아직 구체적으로 테스트하지 않았습니다. 따라서 다른 사람이 확인할 수 있다면 감사하겠습니다.
TamusJRoyce

나는 이미 그것을 테스트했다. 나는 일종의 Nullable유형 을 만들어야 했지만 의미가 다릅니다. 내 상황에서 나는 null유효한 가치로 지원해야하며 전혀 가치도 지원하지 않아야합니다. 그래서 Optional유형을 만들었습니다 . null값 을 지원 해야했기 때문에 구현의 Nullable일부로 값 을 처리하기위한 코드도 구현해야했습니다. 그것이이 코드의 출처입니다.
CARLOS LOTH

9
이 솔루션이 잘못되었다고 생각합니다. Nullable 값 유형을 object 유형의 매개 변수를 예상하는 메소드에 인수로 전달하면 boxing이 발생해야합니다. Nullable은 값 형식이며 권투 변환 결과는 참조 형식입니다. 박스형 널 입력 가능 항목이 없습니다. 이 방법이 항상 false를 반환한다고 생각합니까?
Mishax

1
다른 답변처럼 그것에 대한 모든 테스트?
Kiquenet

5
권투 가치 때문에 작동하지 않습니다. 항상 FALSE를 반환합니다.
N Rocking

10

여기에는 두 가지 문제가 있습니다. 1) 유형이 널 입력 가능 여부를 테스트; 2) 객체가 nullable Type을 나타내는 지 테스트

문제 1 (유형 테스트)의 경우 내 시스템에서 사용한 솔루션은 다음과 같습니다. TypeIsNullable-check solution

문제 2 (객체 테스트)의 경우 위의 Dean Chalk 솔루션은 값 유형에 대해 작동하지만 <T> 과부하를 사용하면 항상 false를 반환하므로 참조 유형에 대해서는 작동하지 않습니다. 참조 유형은 본질적으로 널 입력 가능하므로 참조 유형 테스트는 항상 true를 리턴해야합니다. 이러한 의미에 대한 설명은 아래의 "널링 가능성"정보를 참조하십시오. 따라서 Dean의 접근 방식에 대한 수정 사항은 다음과 같습니다.

    public static bool IsObjectNullable<T>(T obj)
    {
        // If the parameter-Type is a reference type, or if the parameter is null, then the object is always nullable
        if (!typeof(T).IsValueType || obj == null)
            return true;

        // Since the object passed is a ValueType, and it is not null, it cannot be a nullable object
        return false; 
    }

    public static bool IsObjectNullable<T>(T? obj) where T : struct
    {
        // Always return true, since the object-type passed is guaranteed by the compiler to always be nullable
        return true;
    }

위의 솔루션에 대한 클라이언트 테스트 코드에 대한 수정 사항은 다음과 같습니다.

    int a = 123;
    int? b = null;
    object c = new object();
    object d = null;
    int? e = 456;
    var f = (int?)789;
    string g = "something";

    bool isnullable = IsObjectNullable(a); // false 
    isnullable = IsObjectNullable(b); // true 
    isnullable = IsObjectNullable(c); // true 
    isnullable = IsObjectNullable(d); // true 
    isnullable = IsObjectNullable(e); // true 
    isnullable = IsObjectNullable(f); // true 
    isnullable = IsObjectNullable(g); // true

IsObjectNullable <T> (T t)에서 Dean의 접근 방식을 수정 한 이유는 원래 접근 방식이 항상 참조 유형에 대해 false를 반환했기 때문입니다. IsObjectNullable과 같은 메소드는 참조 유형 값을 처리 할 수 ​​있어야하고 모든 참조 유형이 본질적으로 널 입력 가능하므로 참조 유형 또는 널이 전달되면 메소드는 항상 true를 리턴해야합니다.

위의 두 가지 방법을 다음과 같은 단일 방법으로 대체하여 동일한 결과를 얻을 수 있습니다.

    public static bool IsObjectNullable<T>(T obj)
    {
        Type argType = typeof(T);
        if (!argType.IsValueType || obj == null)
            return true;
        return argType.IsGenericType && argType.GetGenericTypeDefinition() == typeof(Nullable<>);
    }

그러나이 마지막 단일 방법 접근법의 문제점은 Nullable <T> 매개 변수를 사용할 때 성능이 저하된다는 것입니다. IsObjectNullable 호출에 Nullable <T> 유형 매개 변수가 사용될 때 컴파일러가 이전에 표시된 두 번째 메서드 오버로드를 선택할 수 있도록 허용하는 것보다이 단일 메서드의 마지막 행을 실행하는 데 훨씬 더 많은 프로세서 시간이 걸립니다. 따라서 최적의 솔루션은 여기에 설명 된 2 가지 방법을 사용하는 것입니다.

주의 사항 :이 방법은 예제에 표시된 것처럼 원본 객체 참조 또는 정확한 사본을 사용하여 호출 된 경우에만 안정적으로 작동합니다. 그러나 nullable 객체가 원래 Nullable <> 형식으로 남아 있지 않고 다른 유형 (예 : 객체 등)으로 박스 화 된 경우이 메서드는 안정적으로 작동하지 않습니다. 이 메소드를 호출하는 코드가 원래의 언 박스 (unboxed) 객체 참조 또는 정확한 사본을 사용하지 않는 경우이 메소드를 사용하여 객체의 null 가능성을 안정적으로 결정할 수 없습니다.

대부분의 코딩 시나리오에서, Null 허용 여부를 결정하려면 대신 참조가 아닌 원래 객체의 Type 테스트에 의존해야합니다 (예 : 코드는 Null 허용 여부를 결정하기 위해 객체의 원래 유형에 액세스해야합니다) 이러한보다 일반적인 경우 IsTypeNullable (링크 참조)은 Null 허용 여부를 결정하는 신뢰할 수있는 방법입니다.

PS- "널링 가능성"정보

별도의 게시물에서 작성한 Null 허용 여부에 대한 설명을 반복해야 하며이 주제를 올바르게 처리하는 데 직접 적용됩니다. 즉, 여기서 논의의 초점은 객체가 일반 Nullable 유형인지 확인하는 것이 아니라 유형의 객체에 null 값을 할당 할 수 있는지 여부를 확인하는 방법이어야한다고 생각합니다. 다시 말해, 객체 유형이 널 입력 가능 여부가 아닌 널 입력 가능 여부를 결정해야한다고 생각합니다. 차이점은 의미론, 즉 무효 성을 결정하기위한 실질적인 이유에 있습니다.

런타임까지 알려지지 않은 유형의 객체 (웹 서비스, 원격 호출, 데이터베이스, 피드 등)를 사용하는 시스템에서 일반적인 요구 사항은 객체에 null을 할당 할 수 있는지 또는 객체에 포함될 수 있는지 여부를 결정하는 것입니다. null 널 입력 가능하지 않은 유형에서 이러한 조작을 수행하면 성능 및 코딩 요구 사항 모두에서 매우 비싼 오류 (일반적으로 예외)가 발생할 수 있습니다. 이러한 문제를 사전에 피하는 것이 가장 선호되는 접근 방식을 취하려면 임의 유형의 오브젝트가 널을 포함 할 수 있는지 판별해야합니다. 즉, 일반적으로 '널링 가능'여부입니다.

매우 실용적이고 일반적인 의미에서 .NET 용어의 Null 허용 여부는 반드시 개체 유형이 Nullable 형식임을 의미하지는 않습니다. 실제로 많은 경우에 객체는 참조 유형을 가지며 널값을 포함 할 수 있으므로 모두 널 입력 가능합니다. 이들 중 어느 것도 널 입력 가능 유형이 없습니다. 따라서 대부분의 시나리오에서 실제적인 목적을 위해서는 Nullable의 구현 종속 개념과 비교하여 nullable의 일반적인 개념에 대해 테스트를 수행해야합니다. 따라서 우리는 .NET Nullable 유형에만 중점을 두지 말고 일반적인 Null 허용 개념에 초점을 맞추는 과정에서 요구 사항과 동작에 대한 이해를 통합하십시오.


8

내가 생각해 낸 가장 간단한 해결책 은 확장 방법으로 Microsoft 솔루션 ( 방법 : Nullable 형식 식별 (C # Programming Guide) )을 구현하는 것입니다.

public static bool IsNullable(this Type type)
{
    return Nullable.GetUnderlyingType(type) != null;
}

그러면 다음과 같이 호출 될 수 있습니다.

bool isNullable = typeof(int).IsNullable();

이것은 클래스 IsNullable()의 다른 모든 IsXxxx()메소드에 적합하기 때문에 액세스하는 논리적 방법으로 보입니다 Type.


1
"! ="대신 "=="를 사용하고 싶지 않습니까?
vkelman

Good spot @vkelman이 변경 작업을 수행하는 대신 Microsoft의 현재 제안을 사용하도록 답변을 업데이트했습니다.
sclarke81

6

널 입력 가능 유형 ( Nullable<int>예 : int?)을 박싱 할 때주의하십시오 .

int? nullValue = null;
object boxedNullValue = (object)nullValue;
Debug.Assert(boxedNullValue == null);

int? value = 10;
object boxedValue = (object)value;
Debug.Assert( boxedValue.GetType() == typeof(int))

실제 참조 유형이되므로 널 입력 가능하다는 사실을 잃게됩니다.


3

어쩌면 약간의 주제이지만 여전히 흥미로운 정보가 있습니다. Nullable.GetUnderlyingType() != null유형이 nullable 인 경우 ID 를 사용 하는 사람들이 많이 있습니다. 이것은 분명히 작동하지만 Microsoft는 다음과 같은 조언을합니다 type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)( http://msdn.microsoft.com/en-us/library/ms366789.aspx 참조) . ).

나는 이것을 성능 측면에서 보았습니다. 아래 테스트 (100 만 회 시도)의 결론은 유형이 nullable 인 경우 Microsoft 옵션이 최상의 성능을 제공한다는 것입니다.

Nullable.GetUnderlyingType () : 1335ms (3 배 느림)

GetGenericTypeDefinition () == typeof (Nullable <>) : 500ms

나는 우리가 적은 시간에 대해 이야기하고 있다는 것을 알고 있지만 모두가 밀리 초를 조정하는 것을 좋아합니다 :-)! 당신이 상사가 당신이 몇 밀리 초를 줄이기를 원한다면 이것은 당신의 구세주입니다 ...

/// <summary>Method for testing the performance of several options to determine if a type is     nullable</summary>
[TestMethod]
public void IdentityNullablePerformanceTest()
{
    int attempts = 1000000;

    Type nullableType = typeof(Nullable<int>);

    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();
    for (int attemptIndex = 0; attemptIndex < attempts; attemptIndex++)
    {
        Assert.IsTrue(Nullable.GetUnderlyingType(nullableType) != null, "Expected to be a nullable"); 
    }

    Console.WriteLine("Nullable.GetUnderlyingType(): {0} ms", stopwatch.ElapsedMilliseconds);

    stopwatch.Restart();

    for (int attemptIndex = 0; attemptIndex < attempts; attemptIndex++)
   {
       Assert.IsTrue(nullableType.IsGenericType && nullableType.GetGenericTypeDefinition() == typeof(Nullable<>), "Expected to be a nullable");
   }

   Console.WriteLine("GetGenericTypeDefinition() == typeof(Nullable<>): {0} ms", stopwatch.ElapsedMilliseconds);
   stopwatch.Stop();
}

1
안녕하세요, 아마도 시간 측정에 문제가있을 수 있습니다. Assert가 결과에 영향을 줄 수 있습니다. Assert없이 테스트 했습니까? 또한 Console.WriteLine은 미터 영역 밖에 있어야합니다. 성능 문제를 수량화하려는 시도는 +1 :).
ipavlu

@ipavlu Console.WriteLine는 실제로 미터 영역 밖에 있습니다;)
nawfal

ipavlu가 언급했듯이 Roel Assert은 루프 외부에 있어야합니다. 둘째, 널 입력 가능하지 않은 항목에 대해서도 테스트하고 잘못된 경우를 테스트해야합니다. 나는 유사한 테스트 (2 nulables 4 비 nullables)를했고, I가 1 ~ 2 초 얻을 GetUnderlyingType과 ~ 일초 GetGenericTypeDefinition즉, GetGenericTypeDefinition두 배 빠른 (안 세 번)입니다.
nawfal

2 개의 nullables와 2 개의 nullable이 아닌 다른 라운드를 했습니까? 이번에 GetUnderlyingType는 2.5 배 느 렸습니다. nullable이 아닌 경우에만-이번에는 목과 목입니다.
nawfal

그러나 더 중요한 GetUnderlyingType것은 nullable을 확인하고 nullable 인 경우 기본 유형을 가져와야 할 때 유용합니다. 이것은 매우 유용하며 패턴이 자주 보입니다 Activator.CreateInstance(Nullable.GetUnderlyingType(type) ?? type). as키워드 와 같 으며 캐스트를 확인하고 결과를 반환합니다. 기본 유형의 nullable을 다시 가져 오려면 GetGenericTypeDefinition검사 를 수행 한 다음 일반 유형을 얻는 것이 좋지 않습니다. 또한 GetUnderlyingType훨씬 더 읽기 쉽고 기억하기 쉽습니다. ~ 1000 번만하고 있다면 신경 쓰지 않을 것입니다.
nawfal

0

이 버전 :

  • 캐싱 결과가 더 빠릅니다.
  • Method (T obj)와 같이 불필요한 변수가 필요하지 않습니다
  • 미완성 :),
  • 한 번만 계산 된 필드가있는 정적 제네릭 클래스

:

public static class IsNullable<T>
{
    private static readonly Type type = typeof(T);
    private static readonly bool is_nullable = type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
    public static bool Result { get { return is_nullable; } }
}

bool is_nullable = IsNullable<int?>.Result;

나는 당신이 그 정적 선언 'is_nullable'로 스스로 대답했다고 생각합니다. 팁 : int로 객체를 선언 하시겠습니까? (object a = (int?) 8;)하고 무슨 일이 일어나는지보십시오.
SoLaR

0

적어도 PLC에서- = C # 6 인 Portable Class Library / .NET Core 에서 다른 모든 것이 실패한 것처럼 여기에 내가 생각해 낸 것이 있습니다.

해결 방법 : 모든 유형의 정적 메소드를 확장 T하고 Nullable<T>및 기본 유형과 일치하는 정적 확장 메서드가 호출 될 것와 일반보다 우선한다는 사실 사용 T확장-방법.

의 경우 T:

public static partial class ObjectExtension
{
    public static bool IsNullable<T>(this T self)
    {
        return false;
    }
}

그리고 Nullable<T>

public static partial class NullableExtension
{
    public static bool IsNullable<T>(this Nullable<T> self) where T : struct
    {
        return true;
    }
}

Reflection 및 type.IsGenericType...을 사용하여 현재 .NET 런타임 세트에서 작동하지 않았습니다. MSDN 설명서도 도움이 되지 않았습니다 .

if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) {…}

.NET Core에서 Reflection API가 상당히 크게 변경 되었기 때문입니다.


0

Microsoft의 제안 된 테스트를 사용 IsGenericType하는 것이 좋지만에 대한 코드 GetUnderlyingType에서 Microsoft는 추가 테스트를 사용하여 일반 유형 정의를 통과하지 않았는지 확인합니다 Nullable<>.

 public static bool IsNullableType(this Type nullableType) =>
    // instantiated generic type only                
    nullableType.IsGenericType &&
    !nullableType.IsGenericTypeDefinition &&
    Object.ReferenceEquals(nullableType.GetGenericTypeDefinition(), typeof(Nullable<>));

-1

이를 수행하는 간단한 방법 :

    public static bool IsNullable(this Type type)
    {
        if (type.IsValueType) return Activator.CreateInstance(type) == null;

        return true;
    }

이것들은 내 단위 테스트이며 모두 통과되었습니다.

    IsNullable_String_ShouldReturn_True
    IsNullable_Boolean_ShouldReturn_False
    IsNullable_Enum_ShouldReturn_Fasle
    IsNullable_Nullable_ShouldReturn_True
    IsNullable_Class_ShouldReturn_True
    IsNullable_Decimal_ShouldReturn_False
    IsNullable_Byte_ShouldReturn_False
    IsNullable_KeyValuePair_ShouldReturn_False

실제 단위 테스트

    [TestMethod]
    public void IsNullable_String_ShouldReturn_True()
    {
        var typ = typeof(string);
        var result = typ.IsNullable();
        Assert.IsTrue(result);
    }

    [TestMethod]
    public void IsNullable_Boolean_ShouldReturn_False()
    {
        var typ = typeof(bool);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_Enum_ShouldReturn_Fasle()
    {
        var typ = typeof(System.GenericUriParserOptions);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_Nullable_ShouldReturn_True()
    {
        var typ = typeof(Nullable<bool>);
        var result = typ.IsNullable();
        Assert.IsTrue(result);
    }

    [TestMethod]
    public void IsNullable_Class_ShouldReturn_True()
    {
        var typ = typeof(TestPerson);
        var result = typ.IsNullable();
        Assert.IsTrue(result);
    }

    [TestMethod]
    public void IsNullable_Decimal_ShouldReturn_False()
    {
        var typ = typeof(decimal);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_Byte_ShouldReturn_False()
    {
        var typ = typeof(byte);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_KeyValuePair_ShouldReturn_False()
    {
        var typ = typeof(KeyValuePair<string, string>);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.