문제

C# 4에 고정 된 버그로 인해 다음 프로그램이 인쇄됩니다. true. (LinqPad에서 시도해보십시오)

void Main() { new Derived(); }

class Base {
    public Base(Func<string> valueMaker) { Console.WriteLine(valueMaker()); }
}
class Derived : Base {
    string CheckNull() { return "Am I null? " + (this == null); }
    public Derived() : base(() => CheckNull()) { }
}

릴리스 모드의 VS2008에서는 InvalidProgrameXception을 던집니다. (디버그 모드에서는 잘 작동합니다)

VS2010 베타 2에서는 컴파일하지 않습니다 (베타 1을 시도하지 않았습니다). 나는 어려운 방법을 배웠다

다른 방법이 있습니까? this == null 순수한 C#에서?

도움이 되었습니까?

해결책

이 관찰은 stackoverflow에 게시되었습니다 다른 질문 오늘 일찍.

마크'에스 그 질문에 대한 큰 대답 사양 (섹션 7.5.7)에 따라 액세스 할 수 없음을 나타냅니다. this 이러한 맥락에서 C# 3.0 컴파일러에서 그렇게하는 능력은 버그입니다. C# 4.0 컴파일러는 사양에 따라 올바르게 작동합니다 (베타 1에서도 컴파일 타임 오류입니다).

§ 7.5.7이 액세스

이 액세스 예약 된 단어로 구성됩니다 this.

이 액세스 :

this

이 액세스 만 허용됩니다 차단하다 인스턴스 생성자, 인스턴스 메소드 또는 인스턴스 액세서의

다른 팁

디버그 모드 바이너리의 원시 디 컴파일 (최적화가없는 반사기)은 다음과 같습니다.

private class Derived : Program.Base
{
    // Methods
    public Derived()
    {
        base..ctor(new Func<string>(Program.Derived.<.ctor>b__0));
        return;
    }

    [CompilerGenerated]
    private static string <.ctor>b__0()
    {
        string CS$1$0000;
        CS$1$0000 = CS$1$0000.CheckNull();
    Label_0009:
        return CS$1$0000;
    }

    private string CheckNull()
    {
        string CS$1$0000;
        CS$1$0000 = "Am I null? " + ((bool) (this == null));
    Label_0017:
        return CS$1$0000;
    }
}

컴파일러링 된 방법은 의미가 없습니다. IL (아래)을 보면 Null에서 메소드를 호출합니다. (!).

   .locals init (
        [0] string CS$1$0000)
    L_0000: ldloc.0 
    L_0001: call instance string CompilerBug.Program/Derived::CheckNull()
    L_0006: stloc.0 
    L_0007: br.s L_0009
    L_0009: ldloc.0 
    L_000a: ret 

릴리스 모드에서 로컬 변수는 최적화되므로 존재하지 않는 변수를 스택으로 푸시하려고합니다.

    L_0000: ldloc.0 
    L_0001: call instance string CompilerBug.Program/Derived::CheckNull()
    L_0006: ret 

(반사기를 C#으로 전환 할 때 반사기 충돌)


편집하다: 누구든지 (Eric Lippert?)가 컴파일러가 왜 ldloc?

나는 그것을 가지고 있었다! (그리고 증거도 얻었습니다)

alt text

이것은 "버그"가 아닙니다. 이것은 유형 시스템을 학대하는 것입니다. 현재 인스턴스에 대한 참조를 전달해서는 안됩니다 (this) 생성자 내의 모든 사람에게.

기본 클래스 생성자 내에서 가상 메소드를 호출하여 유사한 "버그"를 만들 수 있습니다.

당신 때문에 ~할 수 있다 나쁜 일을하는 것이 a를 의미하지는 않습니다 벌레 당신이 그것에 대해 조금 얻을 때.

나는 틀릴 수 있지만 당신의 대상이 null 어디에나 시나리오가 없을 것입니다 this 적용됩니다.

예를 들어, 어떻게 전화 하시겠습니까? CheckNull?

Derived derived = null;
Console.WriteLine(derived.CheckNull()); // this should throw a NullReferenceException

이것이 당신이 찾고있는 것인지 확실하지 않습니다

    public static T CheckForNull<T>(object primary, T Default)
    {
        try
        {
            if (primary != null && !(primary is DBNull))
                return (T)Convert.ChangeType(primary, typeof(T));
            else if (Default.GetType() == typeof(T))
                return Default;
        }
        catch (Exception e)
        {
            throw new Exception("C:CFN.1 - " + e.Message + "Unexpected object type of " + primary.GetType().ToString() + " instead of " + typeof(T).ToString());
        }
        return default(T);
    }

예 : userId = CheckFornull (request.queryString [ "userId"], 147);

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top