C # 또는 .NET에서 최악의 문제는 무엇입니까? [닫은]

최근에 DateTime객체로 작업하고 있었고 다음과 같이 썼습니다.

DateTime dt = DateTime.Now;
dt.AddDays(1);
return dt; // still today's date! WTF?

에 대한 인텔리전스 문서에 AddDays()따르면 날짜에 날짜를 추가하지만 날짜가 추가되지 않은 날짜를 반환 하므로 다음과 같이 작성해야합니다.

DateTime dt = DateTime.Now;
dt = dt.AddDays(1);
return dt; // tomorrow's date

이것은 전에 여러 번 물린 적이 있기 때문에 최악의 C # gotcha를 카탈로그 화하는 것이 유용 할 것이라고 생각했습니다.



답변

private int myVar;
public int MyVar
{
    get { return MyVar; }
}

블 람모. 스택 추적없이 앱이 충돌합니다. 항상 일어난다.

( 게터에서 MyVar소문자 대신 통지 자본 myVar)


답변

Type.GetType

내가 많은 사람들을 물린 것을 보았습니다 Type.GetType(string). 그들은 왜 자신의 어셈블리에서 유형에 대해 작동하는지 궁금 System.String하지만 일부 유형은 그렇지 않지만 궁금합니다 System.Windows.Forms.Form. 답은 현재 어셈블리와에서만 볼 수 있다는 것입니다 mscorlib.


익명의 방법

C # 2.0은 익명의 메서드를 도입하여 다음과 같은 불쾌한 상황을 초래했습니다.

using System;
using System.Threading;

class Test
{
    static void Main()
    {
        for (int i=0; i < 10; i++)
        {
            ThreadStart ts = delegate { Console.WriteLine(i); };
            new Thread(ts).Start();
        }
    }
}

그게 무엇을 인쇄합니까? 글쎄, 그것은 전적으로 일정에 달려 있습니다. 10 개의 숫자를 인쇄하지만 0, 1, 2, 3, 4, 5, 6, 7, 8, 9는 인쇄하지 않을 것입니다. 문제는 i변수가 델리게이트 생성 시점의 값이 아니라 캡처 된 변수라는 것입니다. 올바른 범위의 추가 로컬 변수를 사용하면 쉽게 해결할 수 있습니다.

using System;
using System.Threading;

class Test
{
    static void Main()
    {
        for (int i=0; i < 10; i++)
        {
            int copy = i;
            ThreadStart ts = delegate { Console.WriteLine(copy); };
            new Thread(ts).Start();
        }
    }
}

반복자 블록의 지연된 실행

이 “가난한 사람의 단위 테스트”는 통과되지 않습니다-왜 안되죠?

using System;
using System.Collections.Generic;
using System.Diagnostics;

class Test
{
    static IEnumerable<char> CapitalLetters(string input)
    {
        if (input == null)
        {
            throw new ArgumentNullException(input);
        }
        foreach (char c in input)
        {
            yield return char.ToUpper(c);
        }
    }

    static void Main()
    {
        // Test that null input is handled correctly
        try
        {
            CapitalLetters(null);
            Console.WriteLine("An exception should have been thrown!");
        }
        catch (ArgumentNullException)
        {
            // Expected
        }
    }
}

대답은 CapitalLetters반복기의 MoveNext()메소드가 처음 호출 될 때까지 코드 소스 내의 코드가 실행되지 않는다는 것 입니다.

brainteasers 페이지 에 다른 이상한 점이 있습니다.


답변

예외 다시 던지기

많은 새로운 개발자를 얻는 문제는 다시 던지기 예외 의미입니다.

많은 시간이 다음과 같은 코드를 본다

catch(Exception e)
{
   // Do stuff 
   throw e;
}

문제는 스택 추적을 지우고 문제 진단을 훨씬 어렵게하여 예외가 발생한 위치를 추적 할 수 없다는 것입니다.

올바른 코드는 인수가없는 throw 문입니다.

catch(Exception)
{
    throw;
}

또는 예외를 다른 것으로 랩핑하고 내부 예외를 사용하여 원래 스택 추적을 가져옵니다.

catch(Exception e)
{
   // Do stuff 
   throw new MySpecialException(e);
}

답변

하이젠 베르크 시계 창

다음과 같이 주문형 작업을 수행하는 경우 심하게 물릴 수 있습니다.

private MyClass _myObj;
public MyClass MyObj {
  get {
    if (_myObj == null)
      _myObj = CreateMyObj(); // some other code to create my object
    return _myObj;
  }
}

이제 이것을 사용하는 다른 코드가 있다고 가정 해 봅시다.

// blah
// blah
MyObj.DoStuff(); // Line 3
// blah

이제 CreateMyObj()메소드 를 디버그하려고합니다 . 따라서 코드에 들어가기 위해 위의 3 행에 중단 점을 두십시오. 좋은 측정을 위해 위의 줄에 중단 점을 지정하고 자체에 _myObj = CreateMyObj();중단 점을 배치하십시오 CreateMyObj().

코드는 3 행에서 중단 점에 도달합니다. 코드로 들어갑니다. _myObj분명히 null 이기 때문에 조건부 코드를 입력 할 것으로 예상됩니다 . 어 … 그래서 … 왜 조건을 건너 뛰고 바로 갔 return _myObj습니까?! _myObj 위로 마우스를 가져 가면 실제로 가치가 있습니다! 어떻게 된거 지?!

대답은 “감시”창이 열려 있기 때문에 IDE가 값을 얻었 기 때문입니다. 특히 “자동”감시 창은 현재 또는 이전 실행 라인과 관련된 모든 변수 / 속성의 값을 표시합니다. Line 3에서 중단 점에 도달하면 감시 창에서 중단 점을 무시하고MyObj 장면 뒤의 가치를 알고 자한다면 중단 점을 무시하고 그 가치에 MyObj대한 통화를 계산 CreateMyObj()했습니다. _myObj! 값을 설정합니다

이것이 제가 이것을 하이젠 버그 감시 창이라고 부르는 이유입니다-당신은 그 값에 영향을 미치지 않으면 서 그 값을 관찰 할 수 없습니다 …

고차!


편집 -@ChristianHayter의 의견은이 문제에 대한 효과적인 해결 방법처럼 보이기 때문에 주요 답변에 포함될 가치가 있다고 생각합니다. 그래서 당신은 게으른로드 속성이있을 때마다 …

[DebuggerBrowsable (DebuggerBrowsableState.Never)] 또는 [DebuggerDisplay ( “<loaded on demand>”)]로 속성을 장식하십시오. – 크리스티안 헤이 터


답변

나를 데려 오는 또 다른 시간이 있습니다.

static void PrintHowLong(DateTime a, DateTime b)
{
    TimeSpan span = a - b;
    Console.WriteLine(span.Seconds);        // WRONG!
    Console.WriteLine(span.TotalSeconds);   // RIGHT!
}

TimeSpan.Seconds 는 시간 범위의 초 부분입니다 (2 분 0 초의 초 값은 0 임).

TimeSpan.TotalSeconds 는 초 단위로 측정 된 전체 시간 범위입니다 (2 분은 총 초 값 120).


답변

이벤트를 후크 해제하지 않았기 때문에 메모리 누수가 발생합니다.

이것은 심지어 내가 아는 선임 개발자들을 사로 잡았습니다.

많은 것들이 포함 된 WPF 양식을 상상해 보시고 어딘가에서 이벤트를 구독하십시오. 구독을 취소하지 않으면 양식을 닫고 참조 해제 한 후에 전체 양식이 메모리에 보관됩니다.

내가 본 문제는 WPF 양식에서 DispatchTimer를 만들고 Tick 이벤트를 구독하는 것이라고 생각합니다. 타이머에서-=를 수행하지 않으면 양식에서 메모리가 누출됩니다!

이 예제에서 테어 다운 코드는

timer.Tick -= TimerTickEventHandler;

WPF 양식 내에 DispatchTimer의 인스턴스를 만들었으므로 특히 까다로워서 가비지 수집 프로세스에서 처리하는 내부 참조라고 생각할 것입니다 … 불행히도 DispatchTimer는 정적 인 내부 구독 및 서비스 목록을 사용합니다. UI 스레드에 대한 요청이므로 정적 클래스에서 참조를 ‘소유’합니다.


답변

MSDN에서 동작이 명확하게 작성 되었기 때문에 실제로 문제가되지는 않지만 반 직관적 인 것으로 나타났기 때문에 목이 부러졌습니다.

Image image = System.Drawing.Image.FromFile("nice.pic");

이 사람 "nice.pic"은 이미지가 폐기 될 때까지 파일을 잠근 상태로 둡니다 . 내가 직면했을 때 나는 아이콘을 즉석에서로드하는 것이 좋았지 만 수십 개의 열려 있고 잠겨있는 파일로 끝나는 것을 처음에는 알지 못했습니다! 이미지는 파일이로드 된 위치를 추적합니다 …

이것을 해결하는 방법? 나는 한 명의 라이너가 일을 할 것이라고 생각했다. 에 대한 추가 매개 변수가 필요 FromFile()했지만 아무것도 없었으므로 이것을 썼습니다 …

using (Stream fs = new FileStream("nice.pic", FileMode.Open, FileAccess.Read))
{
    image = System.Drawing.Image.FromStream(fs);
}