C # /. NET에서 매개 변수를 nullable이 아닌 것으로 표시 하시겠습니까?


99

nullC # /. NET에서 전달되는 것을 방지하는 함수 매개 변수에 할당 할 수있는 간단한 특성 또는 데이터 계약이 있습니까? 이상적으로 이것은 컴파일 타임에 리터럴 null이 어디에도 사용되지 않고 런타임에 사용되지 않는지 확인합니다 ArgumentNullException.

현재 나는 다음과 같이 씁니다.

if (null == arg)
  throw new ArgumentNullException("arg");

... 내가 기대하지 않는 모든 논쟁에 대해 null.

같은 메모 Nullable<>에서 다음이 실패 하는 것과 반대되는 점이 있습니까?

NonNullable<string> s = null; // throw some kind of exception

7
최신 버전의 C #에서는 "nameof ()"사용이 더 잘 작동합니다. throw new ArgumentNullException (nameof (arg)); 그런 식으로, 당신은 당신의 throw 문에 잔물결 경우, 이름을 리팩토링 경우
Flydog57

C # 8은 이제 프로젝트에서 켤 수있는 컴파일러 옵션 인 nullable 참조 형식을 지원합니다. docs.microsoft.com/en-us/dotnet/csharp/nullable-references
Paul Stegler

답변:


69

불행히도 컴파일 타임에는 사용할 수있는 것이 없습니다.

최근에 내 블로그에 게시 한 새 구조체와 변환을 사용 하는 약간의 해키 솔루션 이 있습니다.

코드 계약 이 포함 된 .NET 4.0에서는 삶이 훨씬 더 좋아질 것입니다. 실제 언어 구문과 비 null 가능성에 대한 지원이 있으면 여전히 좋지만 코드 계약은 많은 도움이 될 것입니다.

또한 MiscUtilThrowIfNull 이라는 확장 메서드가 있어 좀 더 간단합니다.

마지막으로 " if (null == arg)"대신 " "을 ( 를) 사용하는 이유가 if (arg == null)있습니까? 후자는 읽기가 더 쉽고 전자가 C에서 해결하는 문제는 C #에 적용되지 않습니다.


2
> 불행히도 컴파일 타임에는 사용할 수있는 것이 없습니다. > ...> 실제 언어 구문을 가지고 있고 비 null 가능성을 지원하는 것이 여전히 좋습니다. 또한 컴파일 타임 오류가 발생하는 것을보고 싶습니다.
AndrewJacksonZA

2
@Jon, 정의 된 bool에 대한 암시 적 캐스트가 발생하면 "if (arg = null)"이 작동하지 않습니까? 나는 비뚤어진 것처럼 보일 수 있습니다 인정하지만 ... 컴파일을한다
토마스 에스 트리 아스

11
@ ThomasS.Trias : 네, 매우 모호한 에지 경우, 결합 이 코드 주위 테스트의 부족과 함께 오타, 거기에, 당신은 문제로 끝날 것입니다. 내가 생각하는 그 시점에서 당신은 :)하지만 더 큰 문제가
존 소총

4
@Jon : 그렇습니다. 나는 내가 사랑하는 요다 상태를 포기할 것 같다. :-)
Thomas S. Trias

1
@SebastianMach : 그 이유 if (null == x)는 자연어 차이 때문 이라고 생각하지 않습니다 . 나는 그것이 사용되지 않는 스타일에 대해 정말 믿는 사례 등을 통해 단지 전파
존 소총

22

이 질문에 엄청나게 늦었다는 것을 알고 있지만 C #의 최신 주요 반복이 릴리스에 가까워지고 릴리스되면 대답이 관련성이 높아질 것이라고 생각합니다. C # 8.0에서는 주요 변경 사항이 발생하고 C #은 모든 유형이 null이 아닌 것으로 간주합니다.

Mads Torgersen에 따르면 :

문제는 null 참조가 매우 유용하다는 것입니다. C #에서는 모든 참조 유형의 기본값입니다. 기본값은 무엇입니까? 변수에 할당 할 다른 값을 결정할 수있을 때까지 변수에는 어떤 다른 값이 있습니까? 채울 때까지 새로 할당 된 참조 배열을 포장 할 수있는 다른 값은 무엇입니까?

또한 때때로 null은 그 자체로 합리적인 값입니다. 때로는 필드에 값이 없다는 사실을 나타내려고합니다. 매개 변수에 "아무것도"전달하지 않아도됩니다. 그러나 때때로 강조됩니다. 그리고 여기에 문제의 또 다른 부분이 있습니다. C #과 같은 언어는 여기에서 null이 좋은 생각인지 아닌지를 표현할 수 없습니다.

따라서 Mads가 설명하는 해상도는 다음과 같습니다.

  1. 참조가 null이 아니기를 원하는 것이 더 일반적이라고 생각합니다. Nullable 참조 유형은 더 희귀 한 유형이므로 (얼마나 많은 정보를 제공 할 수있는 좋은 데이터가 없더라도) 새 주석이 필요한 유형입니다.

  2. 언어에는 이미 nullable 값 유형의 개념과 구문이 있습니다. 둘 사이의 비유는 언어 추가를 개념적으로 더 쉽고 언어 적으로 더 간단하게 만들 것입니다.

  3. 적극적으로 원한다고 결정하지 않는 한 귀찮은 null 값으로 자신이나 소비자에게 부담을주지 않는 것이 옳은 것 같습니다. Null이없는 것이 아니라 명시 적으로 옵트 인해야하는 것이어야합니다.

원하는 기능의 예 :

public class Person
{
     public string Name { get; set; } // Not Null
     public string? Address { get; set; } // May be Null
}

미리보기는 Visual Studio 2017, 15.5.4+ 미리보기에서 사용할 수 있습니다.


1
이것이 C # 8.0의 일부가되었는지 아는 사람이 있습니까?
TroySteven

@TroySteven 예, Visual Studio의 설정을 통해 선택해야합니다.
Greg

@TroySteven 여기에 문서가 있습니다. docs.microsoft.com/en-us/dotnet/csharp/nullable-references
그렉

좋습니다. 작동을 시작하기 전에 활성화해야하는 것 같습니다. 이전 버전과의 호환성에 좋습니다.
TroySteven

15

나는 이것이 아주 오래된 질문이라는 것을 알고 있지만 이것은 여기에서 누락되었습니다.

ReSharper / Rider를 사용하는 경우 Annotated Framework를 사용할 수 있습니다 .

편집 : 나는이 대답에 대해 무작위 -1을 얻었습니다. 괜찮아. 다만 그것이 알고 아직도 그것을 # 8.0 + 프로젝트를 더 이상 C의 권장 방식 아니더라도, 유효 (참조, 이유를 이해하는 그렉의 답변을 ).


1
흥미롭게도 컴파일 된 애플리케이션은 기본적으로 JetBrains.Annotations.dll에 대한 참조가 없으므로 애플리케이션과 함께 배포 할 필요가 없습니다. JetBrains 주석을 사용하여 ReSharper 검사를 개선하는 방법
Lu55

9

엔터프라이즈 라이브러리에서 유효성 검사기를 확인하십시오. 다음과 같이 할 수 있습니다.

private MyType _someVariable = TenantType.None;
[NotNullValidator(MessageTemplate = "Some Variable can not be empty")]
public MyType SomeVariable {
    get {
        return _someVariable;
    }
    set {
        _someVariable = value;
    }
}

그런 다음 코드에서 유효성을 검사하려는 경우 :

Microsoft.Practices.EnterpriseLibrary.Validation.Validator myValidator = ValidationFactory.CreateValidator<MyClass>();

ValidationResults vrInfo = InternalValidator.Validate(myObject);

0

가장 예쁘지는 않지만 :

public static bool ContainsNullParameters(object[] methodParams)
{
     return (from o in methodParams where o == null).Count() > 0;
}

ContainsNullParameters 메서드에서도 더 창의적인 결과를 얻을 수 있습니다.

public static bool ContainsNullParameters(Dictionary<string, object> methodParams, out ArgumentNullException containsNullParameters)
       {
            var nullParams = from o in methodParams
                             where o.Value == null
                             select o;

            bool paramsNull = nullParams.Count() > 0;


            if (paramsNull)
            {
                StringBuilder sb = new StringBuilder();
                foreach (var param in nullParams)
                    sb.Append(param.Key + " is null. ");

                containsNullParameters = new ArgumentNullException(sb.ToString());
            }
            else
                containsNullParameters = null;

            return paramsNull;
        }

물론 인터셉터 또는 리플렉션을 사용할 수 있지만 오버 헤드가 거의없이 따라 가거나 사용하기 쉽습니다.


3
아주 나쁜 연습 같은 쿼리를 사용 : return (from o in methodParams where o == null).Count() > 0; 사용 : return methodParams.Any(o=>o==null);그것은 큰 컬렉션에서 훨씬 더 빨리 될 것입니다
Yavanosta

예외를 전달하는 이유는 무엇입니까? 그냥 던지지 않는 이유는 무엇입니까?
Martin Capodici

-4

Ok이 답변은 조금 늦었지만 여기에 해결 방법이 있습니다.

public static string Default(this string x)
{
    return x ?? "";
}

이 확장 방법을 사용하면 null 및 빈 문자열을 동일한 것으로 처리 할 수 ​​있습니다.

if (model.Day.Default() == "")
{
    //.. Do something to handle no Day ..
}

모든 곳에서 default를 호출해야한다는 것을 기억해야하므로 이상적이지는 않지만 하나의 솔루션입니다.


5
이것이 (x == null) 검사보다 더 좋고 / 쉽습니까? 또는 String.IsNotNullOrEmpty 함수.
Batavia

string.IsNotNullOrEmpty당신이 신경 쓰는 것을 왼쪽에 두는 설탕 보다 훨씬 낫지 않습니다 . 다른 함수 (길이, 연결) 등에 공급할 수 있습니다. 약간 더 좋습니다.
Martin Capodici

@MartinCapodici 또한 이것은 null ( ) Default()에 대해 인스턴스 메서드 ( ) 를 호출해도 안전하다는 환상을 만듭니다 . 나는 확장 메소드가 null에 대해 검사되지 않는다는 것을 알고 있지만 내 눈은 인식하지 못하고 이미 코드를 상상했습니다 . :)model.Day?model?.Day?.Default()
Alb
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.