IT

C #에서 null 검사를 수행하는 더 깨끗한 방법?

lottoking 2020. 5. 19. 08:23
반응형

C #에서 null 검사를 수행하는 더 깨끗한 방법? [복제]


이 질문에는 이미 답변이 있습니다.

이 인터페이스가 있다고 가정하겠습니다.

interface IContact
{
    IAddress address { get; set; }
}

interface IAddress
{
    string city { get; set; }
}

class Person : IPerson
{
    public IContact contact { get; set; }
}

class test
{
    private test()
    {
        var person = new Person();
        if (person.contact.address.city != null)
        {
            //this will never work if contact is itself null?
        }
    }
}

Person.Contact.Address.City != null (이것은 City가 null인지 아닌지를 확인하는 것입니다.)

그러나 주소, 연락처 또는 사람 자체가 null 인 경우이 검사가 실패합니다.

현재 내가 생각할 수있는 한 가지 해결책은 다음과 같습니다.

if (Person != null && Person.Contact!=null && Person.Contact.Address!= null && Person.Contact.Address.City != null)

{ 
    // Do some stuff here..
}

더 깔끔한 방법이 있습니까?

나는 null수표가으로 끝나는 것을 정말로 좋아하지 않습니다 (something == null). 대신 방법과 같은 것을 할 수있는 또 다른 좋은 방법이 something.IsNull()있습니까?


일반적인 방식으로, 표현식 트리를 사용하여 확장 메소드로 확인할 수 있습니다.

if (!person.IsNull(p => p.contact.address.city))
{
    //Nothing is null
}

전체 코드 :

public class IsNullVisitor : ExpressionVisitor
{
    public bool IsNull { get; private set; }
    public object CurrentObject { get; set; }

    protected override Expression VisitMember(MemberExpression node)
    {
        base.VisitMember(node);
        if (CheckNull())
        {
            return node;
        }

        var member = (PropertyInfo)node.Member;
        CurrentObject = member.GetValue(CurrentObject,null);
        CheckNull();
        return node;
    }

    private bool CheckNull()
    {
        if (CurrentObject == null)
        {
            IsNull = true;
        }
        return IsNull;
    }
}

public static class Helper
{
    public static bool IsNull<T>(this T root,Expression<Func<T, object>> getter)
    {
        var visitor = new IsNullVisitor();
        visitor.CurrentObject = root;
        visitor.Visit(getter);
        return visitor.IsNull;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Person nullPerson = null;
        var isNull_0 = nullPerson.IsNull(p => p.contact.address.city);
        var isNull_1 = new Person().IsNull(p => p.contact.address.city);
        var isNull_2 = new Person { contact = new Contact() }.IsNull(p => p.contact.address.city);
        var isNull_3 =  new Person { contact = new Contact { address = new Address() } }.IsNull(p => p.contact.address.city);
        var notnull = new Person { contact = new Contact { address = new Address { city = "LONDON" } } }.IsNull(p => p.contact.address.city);
    }
}

null 참조를 확인하는 것보다 코드에 더 큰 문제가있을 수 있습니다. 그것이 의미하는 것처럼, 당신은 아마도 데메테르법칙을 위반하고있을 것입니다 .

Demeter of Law는 자신을 반복하지 않는 것과 같은 휴리스틱 중 하나로서 유지 관리하기 쉬운 코드를 작성하는 데 도움이됩니다. 프로그래머에게 즉각적인 범위에서 너무 멀리 떨어진 것은 접근하지 말라고 지시합니다. 예를 들어 다음 코드가 있다고 가정합니다.

public interface BusinessData {
  public decimal Money { get; set; }
}

public class BusinessCalculator : ICalculator {
  public BusinessData CalculateMoney() {
    // snip
  }
}

public BusinessController : IController {
  public void DoAnAction() {
    var businessDA = new BusinessCalculator().CalculateMoney();
    Console.WriteLine(businessDA.Money * 100d);
  }
}

DoAnAction방법은 데메테르 법칙을 위반합니다. 한 함수에서 BusinessCalcualtor, a BusinessData및 a에 액세스 합니다 decimal. 즉, 다음과 같이 변경하면 회선을 리팩토링해야합니다.

  • BusinessCalculator.CalculateMoney()변경 사항 의 리턴 유형 .
  • BusinessData.Money변경 유형

상황을 고려할 때 이러한 변경이 발생할 가능성이 높습니다. 이와 같은 코드가 코드베이스 전체에 작성되면 이러한 변경을 수행하는 데 비용이 많이들 수 있습니다. 게다가, 그것은 당신 유형 BusinessController모두에 결합되어 있음을 의미합니다 .BusinessCalculatorBusinessData

이 상황을 피하는 한 가지 방법은 다음과 같이 코드를 다시 작성하는 것입니다.

public class BusinessCalculator : ICalculator {
  private BusinessData CalculateMoney() {
    // snip
  }
  public decimal CalculateCents() {
    return CalculateMoney().Money * 100d;
  }
}

public BusinessController : IController {
  public void DoAnAction() {
    Console.WriteLine(new BusinessCalculator().CalculateCents());
  }
}

이제 위의 변경 중 하나를 수행하면 하나의 코드 조각 인 리 팩터 만 리팩토링하면됩니다 BusinessCalculator.CalculateCents(). BusinessController대한 종속성을 제거 했습니다 BusinessData.


코드에 비슷한 문제가 있습니다.

interface IContact
{
    IAddress address { get; set; }
}

interface IAddress
{
    string city { get; set; }
}

class Person : IPerson
{
    public IContact contact { get; set; }
}

class Test {
  public void Main() {
    var contact = new Person().contact;
    var address = contact.address;
    var city = address.city;
    Console.WriteLine(city);
  }
}

다음과 같이 변경 한 경우, 내가 작성한 주요 메소드 또는 널 검사를 리팩터링해야합니다.

  • IPerson.contact변경 유형
  • IContact.address변경 유형
  • IAddress.city변경 유형

단순히 null 검사를 다시 작성하는 것보다 코드의 더 깊은 리팩토링을 고려해야한다고 생각합니다.


나는 데메테르 법칙을 따르는 것이 부적절하다고 생각합니다. (결국 "법칙"이라하더라도, 이는 견고하고 빠른 규칙이 아닌 휴리스틱입니다.)

특히, 나는 다음과 같은 경우에 생각합니다.

  1. 프로그램의 지속성 계층에 저장된 레코드를 나타내는 일부 클래스가 있으며
  2. 앞으로 해당 클래스를 리팩터링 할 필요가 없다고 확신합니다.

이러한 클래스를 구체적으로 다룰 때는 데메테르 법칙을 무시하는 것이 허용됩니다. 이는 애플리케이션이 작업하는 데이터를 나타내므로 한 데이터 오브젝트에서 다른 데이터 오브젝트로 도달하면 프로그램의 정보를 탐색하는 방법입니다. 위의 예에서 Demeter of Law를 위반하여 발생한 커플 링은 훨씬 더 심각했습니다. 스택 중앙의 비즈니스 로직 계산기를 통해 스택 맨 위 근처의 컨트롤러에서 데이터 클래스로 연결하는 중입니다. 지속성 계층에서.

이름이 좋아 함께 때문에 데메테르의 법칙이 발생할 가능성이있는 예외를 가지고 Person, Contact그리고 Address그들이 데이터 레이어 포항 강판 수 있습니다처럼, 수업 모습. 이 경우 미래에 다시 리팩터링 할 필요가 없다고 확신하는 경우 특정 상황에서 Demeter of Law를 무시할 수 있습니다.


당신의 경우에 당신은 사람을 위해 속성을 만들 수 있습니다

public bool HasCity
{
   get 
   { 
     return (this.Contact!=null && this.Contact.Address!= null && this.Contact.Address.City != null); 
   }     
}

하지만 여전히 사람이 null인지 확인해야합니다.

if (person != null && person.HasCity)
{

}

다른 질문에, 문자열의 경우이 방법으로 null 또는 비어 있는지 확인할 수도 있습니다.

string s = string.Empty;
if (!string.IsNullOrEmpty(s))
{
   // string is not null and not empty
}
if (!string.IsNullOrWhiteSpace(s))
{
   // string is not null, not empty and not contains only white spaces
}

완전히 다른 옵션 (잘 사용되지 않는다고 생각)은 null 객체 패턴 입니다. 특정 상황에서 이것이 의미가 있는지 말하기는 어렵지만 시도해 볼 가치가 있습니다. 요컨대, 대신 구현 하는 NullContact구현, NullAddress구현 등이 있습니다 null. 이런 식으로, 대부분의 null 검사를 제거 할 수 있습니다. 물론 이러한 구현을 디자인 할 때 약간의 비용이 소요됩니다.

아담이 그의 의견에서 지적했듯이, 이것은 당신이 쓸 수있게합니다

if (person.Contact.Address.City is NullCity)

실제로 필요한 경우. 물론 이것은 도시가 실제로 사소한 대상이라면 의미가 있습니다 ...

또한, 널 객체는 싱글 톤으로 구현 될 수있다 (예를 들어, 봐 여기 널 객체 패턴의 사용에 관한 몇 가지 구체적인 지침과 여기에 C #에서 싱글에 관한 지침)은 고전적인 비교를 사용할 수 있습니다.

if (person.Contact.Address.City == NullCity.Instance)

개인적으로 패턴에 익숙하지 않은 사람들이 읽기 쉽다고 생각하기 때문에이 방법을 선호합니다.


2014 년 4 월 28 일 업데이트 : C # vNext에 대해 Null 전파가 계획되어 있습니다.


널 검사 전파보다 더 큰 문제가 있습니다. 다른 개발자 이해할 수있는 읽을 수있는 코드를 목표로 하고 있지만, 말이 많지만 예제는 좋습니다.

자주 수행되는 검사 인 경우 Person클래스 내부에서 속성 또는 메서드 호출로 캡슐화하는 것이 좋습니다.


그건 말도 안되고 Func제네릭!

나는 이것을하지 않을 것이지만 여기에 다른 대안이 있습니다.

class NullHelper
{
    public static bool ChainNotNull<TFirst, TSecond, TThird, TFourth>(TFirst item1, Func<TFirst, TSecond> getItem2, Func<TSecond, TThird> getItem3, Func<TThird, TFourth> getItem4)
    {
        if (item1 == null)
            return false;

        var item2 = getItem2(item1);

        if (item2 == null)
            return false;

        var item3 = getItem3(item2);

        if (item3 == null)
            return false;

        var item4 = getItem4(item3);

        if (item4 == null)
            return false;

        return true;
    }
}

전화 :

    static void Main(string[] args)
    {
        Person person = new Person { Address = new Address { PostCode = new Postcode { Value = "" } } };

        if (NullHelper.ChainNotNull(person, p => p.Address, a => a.PostCode, p => p.Value))
        {
            Console.WriteLine("Not null");
        }
        else
        {
            Console.WriteLine("null");
        }

        Console.ReadLine();
    }

두 번째 질문은

나는 null 검사가 (something == null)처럼되는 것을 정말로 좋아하지 않습니다. 대신 something.IsNull () 메서드와 같은 작업을 수행하는 또 다른 좋은 방법이 있습니까?

확장 방법을 사용하여 해결할 수 있습니다.

public static class Extensions
{
    public static bool IsNull<T>(this T source) where T : class
    {
        return source == null;
    }
}

어떤 이유로 더 많은 '최상의'솔루션 중 하나를 사용하는 것이 마음에 들지 않으면 내 블로그 게시물에 설명 된 솔루션을 확인하십시오 . 식 트리를 사용하여 식을 평가하기 전에 값이 null인지 확인합니다. 그러나 성능을 수용 가능하게 유지하기 위해 IL 코드를 생성하고 캐시합니다.

이 솔루션을 사용하면 다음과 같이 작성할 수 있습니다.

string city = person.NullSafeGet(n => n.Contact.Address.City);

당신은 쓸 수 있습니다:

public static class Extensions
    {
        public static bool IsNull(this object obj)
        {
            return obj == null;
        }
    }

그리고:

string s = null;
if(s.IsNull())
{

}

때때로 이것은 의미가 있습니다. 그러나 개인적으로 나는 그런 것들을 피할 것입니다 ... 왜 이것이 실제로 null 인 객체의 메소드를 호출 할 수 있는지 분명하지 않기 때문입니다.


다음 method과 같이 별도로 수행하십시오 .

private test()
{
    var person = new Person();
    if (!IsNull(person))
    {
        // Proceed
              ........

어디 IsNull methodIS

public bool IsNull(Person person)
{
    if(Person != null && 
       Person.Contact != null && 
       Person.Contact.Address != null && 
       Person.Contact.Address.City != null)
          return false;
    return true;
}

C #이 필요합니까, 아니면 .NET 만 원 하십니까? 다른 .NET 언어를 혼합 할 수 있으면 Oxygene을 살펴보십시오 . .NET을 대상으로하는 놀랍고 현대적인 OO 언어입니다 (Java 및 Cocoa 도 마찬가지입니다). 기본적으로 정말 놀라운 툴체인입니다.

Oxygene에는 콜론 연산자가있어 원하는 것을 정확하게 수행 할 수 있습니다. 기타 언어 기능 페이지 에서 인용하려면 :

콜론 ( ":") 연산자

Oxygene에서는 많은 언어 에서처럼 "."의 영향을 받았습니다. 연산자는 다음과 같은 클래스 또는 객체에서 멤버를 호출하는 데 사용됩니다.

var x := y.SomeProperty;

이것은 "y"에 포함 된 객체를 "역 참조"하고 (이 경우) getter 속성을 호출하고 해당 값을 반환합니다. "y"가 할당되지 않은 경우 (예 : "nil") 예외가 발생합니다.

":"연산자는 거의 같은 방식으로 작동하지만 할당되지 않은 객체에서 예외를 발생시키는 대신 결과는 단순히 nil이됩니다. Objective-C에서 온 개발자에게는 익숙한데 이는 [] 구문을 사용하여 Objective-C 메서드가 호출하는 방식이기도합니다.

... (싹둑)

":"가 실제로 빛을 발하는 곳은 체인의 속성에 액세스 할 때입니다. 예를 들어, 다음 코드는

var y := MyForm:OkButton:Caption:Length;

체인의 개체 중 하나라도 형식, 단추 또는 캡션이없는 경우 오류없이 실행되고 nil을 반환합니다.


try
{
  // do some stuff here
}
catch (NullReferenceException e)
{
}

실제로이 작업을 수행하지 마십시오. null 검사를 수행하고 가장 적합한 서식을 찾으십시오.


이것에 유용한 확장 기능이 있습니다. ValueOrDefault (). 예상되는 예외 (NRE 또는 IOE)가 발생하면 람다 명령문을 승인하고 평가하여 평가 된 값 또는 기본값을 리턴합니다.

    /// <summary>
    /// Provides a null-safe member accessor that will return either the result of the lambda or the specified default value.
    /// </summary>
    /// <typeparam name="TIn">The type of the in.</typeparam>
    /// <typeparam name="TOut">The type of the out.</typeparam>
    /// <param name="input">The input.</param>
    /// <param name="projection">A lambda specifying the value to produce.</param>
    /// <param name="defaultValue">The default value to use if the projection or any parent is null.</param>
    /// <returns>the result of the lambda, or the specified default value if any reference in the lambda is null.</returns>
    public static TOut ValueOrDefault<TIn, TOut>(this TIn input, Func<TIn, TOut> projection, TOut defaultValue)
    {
        try
        {
            var result = projection(input);
            if (result == null) result = defaultValue;
            return result;
        }
        catch (NullReferenceException) //most reference types throw this on a null instance
        {
            return defaultValue;
        }
        catch (InvalidOperationException) //Nullable<T> throws this when accessing Value
        {
            return defaultValue;
        }
    }

    /// <summary>
    /// Provides a null-safe member accessor that will return either the result of the lambda or the default value for the type.
    /// </summary>
    /// <typeparam name="TIn">The type of the in.</typeparam>
    /// <typeparam name="TOut">The type of the out.</typeparam>
    /// <param name="input">The input.</param>
    /// <param name="projection">A lambda specifying the value to produce.</param>
    /// <returns>the result of the lambda, or default(TOut) if any reference in the lambda is null.</returns>
    public static TOut ValueOrDefault<TIn, TOut>(this TIn input, Func<TIn, TOut> projection)
    {
        return input.ValueOrDefault(projection, default(TOut));
    }

특정 기본값을 사용하지 않는 과부하는 참조 유형에 대해 null을 반환합니다. 시나리오에서 작동합니다.

class test
{
    private test()
    {
        var person = new Person();
        if (person.ValueOrDefault(p=>p.contact.address.city) != null)
        {
            //the above will return null without exception if any member in the chain is null
        }
    }
}

이러한 참조 체인은 예를 들어 ORM 도구를 사용하고 클래스를 가능한 한 순수하게 유지하려는 경우에 발생할 수 있습니다. 이 시나리오에서는 잘 피할 수 없다고 생각합니다.

다음과 같은 확장 메소드 "family"가 있는데,이 메소드는 호출 된 오브젝트가 널인지 확인하고, 그렇지 않은 경우 요청 된 특성 중 하나를 리턴하거나 일부 메소드를 실행합니다. 이것은 물론 참조 유형에 대해서만 작동하므로 해당하는 일반적인 제약 조건이 있습니다.

public static TRet NullOr<T, TRet>(this T obj, Func<T, TRet> getter) where T : class
{
    return obj != null ? getter(obj) : default(TRet);
}

public static void NullOrDo<T>(this T obj, Action<T> action) where T : class
{
    if (obj != null)
        action(obj);
}

이러한 방법은 수동 솔루션에 비해 오버 헤드가 거의 없으며 (반사, 표현식 트리 없음), 더 좋은 구문 (IMO)을 얻을 수 있습니다.

var city = person.NullOr(e => e.Contact).NullOr(e => e.Address).NullOr(e => e.City);
if (city != null)
    // do something...

또는 방법 :

person.NullOrDo(p => p.GoToWork());

그러나 코드 길이가 너무 많이 변하지 않았다고 분명히 주장 할 수 있습니다.


제 생각에 , 평등 연산자는 참조 평등을위한 더 안전하고 좋은 방법이 아닙니다 .

항상 사용하는 것이 좋습니다 ReferenceEquals(obj, null). 이것은 항상 작동합니다. 반면에 항등 연산자 (==)는 오버로드 될 수 있으며 참조 대신 값이 동일한 지 검사 할 수 있으므로 ReferenceEquals()더 안전하고 좋은 방법이라고합니다.

class MyClass {
   static void Main() {
      object o = null;
      object p = null;
      object q = new Object();

      Console.WriteLine(Object.ReferenceEquals(o, p));
      p = q;
      Console.WriteLine(Object.ReferenceEquals(p, q));
      Console.WriteLine(Object.ReferenceEquals(o, p));
   }
}

참조 : MSDN article Object.ReferenceEquals Method .

또한 null 값에 대한 내 생각은 다음과 같습니다.

  • 일반적으로 누구나 데이터가 없음을 나타내려는 경우 null 값을 반환하는 것이 가장 좋습니다.

  • 개체가 null이 아니고 비어있는 경우 데이터가 반환되었음을 나타내며 null을 반환하면 아무것도 반환되지 않았 음을 나타냅니다.

  • 또한 IMO는 null을 반환하면 개체의 멤버에 액세스하려고하면 null 예외가 발생하여 버그가있는 코드를 강조 표시하는 데 유용 할 수 있습니다.

C #에는 두 가지 종류의 평등이 있습니다.

  • 참조 평등
  • 가치 평등.

타입이 불변 인 경우, 참조 평등 대신에 값 평등을 비교하기 위해 과부하 연산자 ==가 유용 할 수 있습니다.

변경 불가능한 유형의 연산자 ==를 대체하지 않는 것이 좋습니다.

자세한 내용은 MSDN 문서 오버로딩 Equals () 및 연산자 == (C # 프로그래밍 안내서) 를 참조하십시오.


C #을 좋아하는 한, 이것은 객체 인스턴스로 직접 작업 할 때 C ++에 대해 좋은 점 중 하나입니다. 일부 선언은 단순히 null이 될 수 없으므로 null을 확인할 필요가 없습니다.

C # 에서이 파이 조각을 얻을 수있는 가장 좋은 방법은 부분적으로 너무 많은 재 디자인 일 수 있습니다.이 경우 다른 답변을 선택하십시오 struct. 구조체가 인스턴스화되지 않은 "default"값 (예 : 0, 0.0, null 문자열)이있는 상황에서 "if (myStruct == null)"을 확인할 필요는 없습니다.

물론 그들의 사용을 이해하지 않고 그들에게로 전환하지 않을 것입니다. 그것들은 값 타입에 사용되는 경향이 있으며 실제로는 큰 데이터 블록에는 사용되지 않는 경향이 있습니다. 한 변수에서 다른 변수로 구조체를 할당 할 때마다 실제로 데이터를 복사하는 경향이 있으며 본질적으로 각 원래 값의 사본을 만듭니다 ( ref키워드로 이를 피할 수 있습니다 -다시 사용하는 것이 아니라 다시 읽으십시오). 그럼에도 불구하고 StreetAddress와 같은 것들에 적합 할 수 있습니다-확실히 null 검사를 원하지 않는 것에 게으르게 사용하지는 않을 것입니다.


"city"변수를 사용하는 목적에 따라 더 깔끔한 방법으로 널 검사를 다른 클래스로 분리 할 수 ​​있습니다. 그렇게하면 데메테르의 법칙을 위반하지 않을 것입니다. 따라서 대신 :

if (person != null && person.contact != null && person.contact.address != null && person.contact.address.city != null)
{ 
    // do some stuff here..
}

당신은 가질 것이다 :

class test
{
    private test()
    {
        var person = new Person();
        if (person != null)
        {
            person.doSomething();
        }
    }
}

...

/* Person class */
doSomething() 
{
    if (contact != null)
    {
        contact.doSomething();
    }
}

...

/* Contact class */
doSomething()
{
    if (address != null) 
    {
        address.doSomething();
    }
}

...

/* Address class */
doSomething()
{
    if (city != null)
    {
        // do something with city
    }
}

다시, 그것은 프로그램의 목적에 달려 있습니다.


어떤 상황에서 그러한 것들이 무효가 될 수 있습니까? null이 코드의 버그를 나타내면 코드 계약을 사용할 수 있습니다. 테스트하는 동안 null이 발생하면 프로덕션 버전에서 사라집니다. 이 같은:

using System.Diagnostics.Contracts;

[ContractClass(typeof(IContactContract))]
interface IContact
{
    IAddress address { get; set; }
}

[ContractClassFor(typeof(IContact))]
internal abstract class IContactContract: IContact
{
    IAddress address
    {
        get
        {
            Contract.Ensures(Contract.Result<IAddress>() != null);
            return default(IAddress); // dummy return
        }
    }
}

[ContractClass(typeof(IAddressContract))]
interface IAddress
{
    string city { get; set; }
}

[ContractClassFor(typeof(IAddress))]
internal abstract class IAddressContract: IAddress
{
    string city
    {
        get
        {
            Contract.Ensures(Contract.Result<string>() != null);
            return default(string); // dummy return
        }
    }
}

class Person
{
    [ContractInvariantMethod]
    protected void ObjectInvariant()
    {
        Contract.Invariant(contact != null);
    }
    public IContact contact { get; set; }
}

class test
{
    private test()
    {
        var person = new Person();
        Contract.Assert(person != null);
        if (person.contact.address.city != null)
        {
            // If you get here, person cannot be null, person.contact cannot be null
            // person.contact.address cannot be null and person.contact.address.city     cannot be null. 
        }
    }
}

물론 가능한 null이 다른 곳에서 오는 경우 이미 데이터를 조정해야합니다. 또한 널 중 하나라도 유효하면 널 (null)이 아닌 것을 계약의 일부로 만들지 말아야하며이를 테스트하고 적절하게 처리해야합니다.


메소드에서 널 점검을 제거하는 한 가지 방법은 다른 곳에서 기능을 캡슐화하는 것입니다. 이를 수행하는 한 가지 방법은 게터와 세터를 이용하는 것입니다. 예를 들어, 이것을하는 대신 :

class Person : IPerson
{
    public IContact contact { get; set; }
}

이 작업을 수행:

class Person : IPerson
{
    public IContact contact 
    { 
        get
        {
            // This initializes the property if it is null. 
            // That way, anytime you access the property "contact" in your code, 
            // it will check to see if it is null and initialize if needed.
            if(_contact == null)
            {
                _contact = new Contact();
            }
            return _contact;
        } 
        set
        {
            _contact = value;
        } 
    }
    private IContact _contact;
}

그런 다음 "person.contact"를 호출 할 때마다 "get"메소드의 코드가 실행되므로 값이 널이면 값이 초기화됩니다.

이 같은 방법론을 모든 유형에 대해 null 일 수있는 모든 속성에 적용 할 수 있습니다. 이 방법의 장점은 1) 인라인으로 널 검사를 수행하지 않아도되며 2) 코드를 더 읽기 쉽게하고 복사-붙여 넣기 오류가 발생하지 않는다는 것입니다.

그러나 속성 중 하나 null 인 경우 (예 : null Contact를 가진 사람이 실제로 도메인에서 무언가를 의미합니까?) 작업을 수행해야하는 상황에 처한 경우이 방법에주의해야합니다. 도움보다는 방해가 될 것입니다. 그러나 문제의 속성 이 null 아니 어야하는 경우이 방법을 사용하면 해당 사실을 매우 깔끔하게 나타낼 수 있습니다.

--jtlovetteiii


모든 클래스에서 인터페이스와 추가 코드를 강제로 구현하지 않도록 리플렉션을 사용할 수 있습니다. 정적 메소드가있는 간단하게 헬퍼 클래스입니다. 이것은 가장 효율적인 방법이 아닐 수도 있고, 나에게 부드럽게, 나는 처녀입니다 (읽기, 멍청한 놈) ..

public class Helper
{
    public static bool IsNull(object o, params string[] prop)
    {
        if (o == null)
            return true;

        var v = o;
        foreach (string s in prop)
        {
            PropertyInfo pi = v.GetType().GetProperty(s); //Set flags if not only public props
            v = (pi != null)? pi.GetValue(v, null) : null;
            if (v == null)
                return true;                                
        }

        return false;
    }
}

    //In use
    isNull = Helper.IsNull(p, "ContactPerson", "TheCity");

만약 당신이 propnames에 오타가 있다면, 결과는 잘못 될 것입니다.

참고 URL : https://stackoverflow.com/questions/17672481/cleaner-way-to-do-a-null-check-in-c

반응형