check - c# operator.




객체가 nullable인지 확인하는 방법은 무엇입니까? (9)

"형식이 nullable인지 확인하는 방법"질문 실제로 "형식이 Nullable<> 인지 확인하는 방법입니다."형식이 일반 형식의 생성 된 형식인지 확인하는 방법 "으로 일반화 할 수 있으므로"Is Nullable<int> Is Is Is Nullable<int> Is? Nullable<int> Nullable<> ? " Nullable<> 만 아니라" List<int> List<> ? "입니다.

제공된 솔루션의 대부분은 Nullable.GetUnderlyingType() 메서드를 사용합니다.이 메서드는 Nullable<> 의 경우에만 작동합니다. 어떤 일반적인 유형에도 적용 할 수있는 일반적인 반사 솔루션을 보지 못했습니다. 그래서이 질문은 이미 오래전에 답변을 받았음에도 불구하고 후손을 위해 여기에 추가하기로했습니다.

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

객체가 Type 아니라 nullable인지 확인하려면 Marc Gravell의 솔루션과 함께 위의 기법을 사용하여 간단한 메서드를 만듭니다.

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

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

주어진 객체가 다른 방법으로 nullable인지 확인하려면 어떻게해야합니까? 다음 메소드를 구현하는 법 ...

bool IsNullableValueType(object o)
{
    ...
}

편집 : nullable 값 형식을 찾고 있는데요. 나는 ref 타입을 염두에 두지 않았다.

//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 값과 비교 true . 내가 원했던 것은 Nullable<bool> 타입의 객체였습니다. Nullable<bool>

그래서 지금은 주위에 일을 내가 o가 nullable 및 obj 주위에 nullable 래퍼를 만들 수 있는지 확인하기로 결정했습니다.


nullable - Nullable<T> 및 참조 유형의 두 가지 유형이 있습니다.

Jon은 상자에 넣으면 형식을 얻는 것이 어렵다는 것을 나에게 시정했지만 제네릭으로 할 수 있습니다. 이것은 실제로 유형 T 테스트하지만 obj 매개 변수를 순수하게 generic 형식 유추 (호출하기 쉽도록)로 사용합니다. 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
}

그러나 이미 값을 객체 변수에 박스로 묶어 두었다면 너무 잘 작동하지 않습니다.


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

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

다른 모든 것들이 실패한 것처럼 보였습니다 - 최소한 PLC에서는 - Portable Class Library / .NET Core > = C # 6

솔루션 : 모든 유형 TNullable<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;
    }
}

리플렉션 사용 및 type.IsGenericType ... 현재 .NET 런타임 집합에서 작동하지 않았습니다. 또한 MSDN 설명서도 도움이되지 않았습니다.

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

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


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

나는 공연의 측면에서 이것을 보았다. 아래의 테스트 (백만 회 시도)의 결론은 형식이 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) Type이 nullable인지 여부를 테스트합니다. 2) 객체가 nullable 유형인지 여부를 확인하기위한 테스트.

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

문제 2 (객체 테스트)의 경우 위의 Dean Chalk의 솔루션은 값 유형에 대해 작동하지만 참조 유형에 대해서는 작동하지 않습니다. 이는 <T> 오버로드를 사용하면 항상 false를 반환하기 때문입니다. 참조 유형은 본질적으로 nullable이므로 참조 유형을 테스트 할 때는 항상 true를 반환해야합니다. 이러한 의미에 대한 설명은 아래의 [null 허용 여부] 정보를 참조하십시오. 따라서 다음은 딘의 접근 방식을 수정 한 것입니다.

    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와 같은 메소드는 참조 유형 값을 처리 할 수 ​​있어야하고 모든 참조 유형은 기본적으로 널 (NULL) 입력 가능하므로 참조 유형이나 널 (null)이 전달되면 메소드는 항상 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> -type 매개 변수를 사용하는 경우 이전에 표시된 두 번째 메서드 오버로드를 선택하는 것보다이 단일 메서드의 마지막 줄을 실행하는 데 훨씬 많은 프로세서 시간이 필요합니다. 따라서 최적의 솔루션은 여기에 설명 된 2 가지 방법을 사용하는 것입니다.

경고 :이 메서드는 예제에 표시된 것처럼 원래의 개체 참조 나 정확한 복사본을 사용하여 호출 한 경우에만 안정적으로 작동합니다. 그러나 nullable 개체가 원래 Nullable <> 형식으로 유지되는 대신 다른 Type (예 : 개체 등)으로 묶인 경우이 메서드는 안정적으로 작동하지 않습니다. 이 메서드를 호출하는 코드가 원래의 상자에 들어 있지 않은 개체 참조 또는 정확한 복사본을 사용하지 않는 경우이 메서드를 사용하여 개체의 Null 허용 여부를 안정적으로 확인할 수 없습니다.

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

추신 - "null 허용 여부"정보

별도의 게시물에서 작성한 null 허용 여부에 대한 설명을 반복해야하며,이 주제는이 주제를 올바르게 해결하는 데 직접 적용됩니다. 즉, 여기서 논의의 초점은 객체가 일반 Nullable 유형인지 확인하는 방법이 아니라 오히려 객체가 해당 유형의 객체에 null 값을 할당 할 수 있는지 여부를 확인하는 것이어야한다고 생각합니다. 즉, 개체 유형이 Nullable인지 여부가 아니라 Nullable인지 여부를 결정해야한다고 생각합니다. 차이점은 의미론에 있습니다. 즉, nullability를 결정하는 실제적인 이유는 일반적으로 중요합니다.

런타임까지 알 수없는 유형의 객체 (웹 서비스, 원격 호출, 데이터베이스, 피드 등)를 사용하는 시스템에서 일반적인 요구 사항은 null을 객체에 할당 할 수 있는지 또는 객체가 포함 할 수 있는지 여부를 확인하는 것입니다 null. Null을 허용하지 않는 유형에 대해 이러한 연산을 수행하면 일반적으로 성능 및 코딩 요구 사항 측면에서 매우 비싼 예외를 생성 할 수 있습니다. 이러한 문제를 사전에 방지하는 매우 바람직한 접근 방식을 취하려면 임의의 Type의 객체가 null을 포함 할 수 있는지 여부를 결정해야합니다. 즉 그것이 일반적으로 'nullable'인지의 여부.

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


이 버전 :

  • 캐싱 결과가 더 빠르며,
  • 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;

이것은 나를 위해 작동하고 간단하게 보인다 :

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

주의 할 점은, boxing nullable 형식 ( 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))

참된 참조 유형이되므로 null이 허용된다는 사실을 잃게됩니다.





nullable