[C#] C #에서 null 개체에 대해 확장 메서드를 호출하면 어떻게됩니까?

메소드가 널값으로 호출되거나 널 참조 예외가 발생합니까?

MyObject myObject = null;
myObject.MyExtensionMethod(); // <-- is this a null reference exception?

이 경우 ‘this’매개 변수가 null인지 확인하지 않아도됩니까?



답변

그것은 잘 작동합니다 (예외 없음). 확장 메서드는 가상 호출을 사용하지 않습니다 (즉, “callvirt”가 아닌 “call”il 명령어 사용). 확장 메서드에 직접 작성하지 않으면 null 검사가 없습니다. 이것은 실제로 몇 가지 경우에 유용합니다.

public static bool IsNullOrEmpty(this string value)
{
    return string.IsNullOrEmpty(value);
}
public static void ThrowIfNull<T>(this T obj, string parameterName)
        where T : class
{
    if(obj == null) throw new ArgumentNullException(parameterName);
}

기타

기본적으로 정적 호출에 대한 호출은 매우 문자 그대로입니다. 즉

string s = ...
if(s.IsNullOrEmpty()) {...}

된다 :

string s = ...
if(YourExtensionClass.IsNullOrEmpty(s)) {...}

널 검사가 분명히없는 곳.


답변

Marc Gravell의 정답에 추가.

이 인수가 널인 것이 확실한 경우 컴파일러에서 경고를받을 수 있습니다.

default(string).MyExtension();

런타임에는 잘 작동하지만 경고가 발생 "Expression will always cause a System.NullReferenceException, because the default value of string is null"합니다.


답변

이미 살펴본 바와 같이 확장 메서드는 단순히 정적 메서드로 영광을주기 때문에 null참조가 전달되지 않고 전달되어 참조 가 호출됩니다 NullReferenceException. 그러나, 그들은 호출자에게 인스턴스 메소드처럼 보이기 때문에 그렇게 행동 해야 합니다 . 그런 다음 대부분의 경우 this매개 변수를 확인 하고이 경우 예외를 발생 시켜야합니다 null. 메소드가 명시 적으로 null값을 처리하고 이름이 아래 예와 같이 적절하게 표시하는 경우에는이를 수행하지 않는 것이 좋습니다.

public static class StringNullExtensions {
  public static bool IsNullOrEmpty(this string s) {
    return string.IsNullOrEmpty(s);
  }
  public static bool IsNullOrBlank(this string s) {
    return s == null || s.Trim().Length == 0;
  }
}

또한 얼마 전에 이것에 관한 블로그 게시물을 작성 했습니다 .


답변

확장 메소드에는 널이 전달됩니다.

메소드가 점검하지 않고 객체에 액세스하려고 시도하면 null이면, 예외가 발생합니다.

여기에있는 사람이 참조가 null을 통과했는지 여부를 확인하는 “IsNull”및 “IsNotNull”확장 메서드를 작성했습니다. 개인적으로 나는 이것이 수차라고 생각하고 오늘의 빛을 보아서는 안되지만 완벽하게 유효한 C #입니다.


답변

다른 사람들이 지적했듯이 null 참조에서 확장 메서드를 호출하면 this 인수가 null이되고 특별한 것은 발생하지 않습니다. 이것은 확장 메소드를 사용하여 가드 절을 작성하는 아이디어를 제공합니다.

를 들어이 기사를 읽을 수 있습니다. 순환 복잡성을 줄이는 방법 : Guard Clause Short 버전은 다음과 같습니다.

public static class StringExtensions
{
    public static void AssertNonEmpty(this string value, string paramName)
    {
        if (string.IsNullOrEmpty(value))
            throw new ArgumentException("Value must be a non-empty string.", paramName);
    }
}

이것은 null 참조에서 호출 할 수있는 문자열 클래스 확장 메소드입니다.

((string)null).AssertNonEmpty("null");

런타임은 null 참조에서 확장 메서드를 성공적으로 호출하기 때문에 호출이 제대로 작동합니다. 그런 다음이 확장 메소드를 사용하여 지저분한 구문없이 guard 절을 구현할 수 있습니다.

    public IRegisteredUser RegisterUser(string userName, string referrerName)
    {

        userName.AssertNonEmpty("userName");
        referrerName.AssertNonEmpty("referrerName");

        ...

    }


답변

확장 메소드는 정적 이므로이 MyObject에 아무것도하지 않으면 문제가되지 않아야하며 빠른 테스트를 통해 확인해야합니다 🙂


답변

읽기 쉽고 세로로 만들고 싶을 때 황금률이 ​​거의 없습니다.

  • 에펠에서 말할만한 가치가 있다고 말하면 메소드에 캡슐화 된 특정 코드는 일부 입력에 대해 작동해야하며 일부 전제 조건을 충족하고 예상 출력을 보장하면 코드를 실행할 수 있다고 말합니다

귀하의 경우-DesignByContract가 손상되었습니다 … null 인스턴스에서 일부 논리를 수행하려고합니다.