C # 또는 .NET에서 최악의 문제는 무엇입니까? [닫은]
최근에 DateTime
객체로 작업하고 있었고 다음과 같이 썼습니다.
DateTime dt = DateTime.Now;
dt.AddDays(1);
return dt; // still today's date! WTF?
intellisense 문서에 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
사용자 의 가치를 계산 했습니다. _myObj! 값을 설정합니다CreateMyObj()
이것이 제가 이것을 하이젠 버그 시계 창이라고 부르는 이유입니다-당신은 그 값에 영향을 미치지 않으면 서 그 값을 관찰 할 수 없습니다 ... :)
고차!
편집 -@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);
}
ASP.NET을 계산하면 webforms 라이프 사이클이 꽤 큰 문제라고 생각합니다. 잘못 작성된 웹 양식 코드를 디버깅하는 데 많은 시간을 보냈습니다. 많은 개발자가 언제 어떤 이벤트 핸들러 (슬프게도 포함)를 사용 해야하는지 실제로 이해하지 못하기 때문입니다.
과부하 == 연산자 및 유형이 지정되지 않은 컨테이너 (배열 목록, 데이터 집합 등) :
string my = "my ";
Debug.Assert(my+"string" == "my string"); //true
var a = new ArrayList();
a.Add(my+"string");
a.Add("my string");
// uses ==(object) instead of ==(string)
Debug.Assert(a[1] == "my string"); // true, due to interning magic
Debug.Assert(a[0] == "my string"); // false
솔루션?
string.Equals(a, b)
문자열 유형을 비교할 때 항상 사용List<string>
두 피연산자가 모두 문자열인지 확인하기 위해 제네릭 을 사용합니다.
[Serializable]
class Hello
{
readonly object accountsLock = new object();
}
//Do stuff to deserialize Hello with BinaryFormatter
//and now... accountsLock == null ;)
이야기의 교훈 : 객체를 역 직렬화 할 때 필드 초기화가 실행되지
DateTime.ToString ( "dd / MM / yyyy") ; 이것은 실제로 것입니다 하지 항상 당신이 / DD MM / YYYY 대신 당신은 위치에 따라 날짜 구분 계정에 국가 별 설정을하고 대체합니다 제공합니다. 따라서 dd-MM-yyyy 또는 이와 유사한 것을 얻을 수 있습니다.
올바른 방법은 DateTime.ToString ( "dd '/'MM '/'yyyy");
DateTime.ToString ( "r") 은 GMT를 사용하는 RFC1123으로 변환되어야합니다. GMT는 UTC에서 1 분의 1 초 내에 있지만 "r"형식 지정 자는 해당 DateTime이 Local로 지정된 경우에도 UTC로 변환되지 않습니다 .
결과적으로 다음과 같은 차이가 발생합니다 (현지 시간이 UTC와 얼마나 떨어져 있는지에 따라 다름).
DateTime.Parse("Tue, 06 Sep 2011 16:35:12 GMT").ToString("r")
> "Tue, 06 Sep 2011 17:35:12 GMT"
으악!
나는이 날짜가 다른 날에 게시되는 것을 보았는데, 잘 모르는 사람들에게는 꽤 애매하고 고통 스럽다고 생각합니다.
int x = 0;
x = x++;
return x;
대부분의 예상대로 1이 아닌 0을 반환합니다.
나는이 파티에 조금 늦었지만 최근에 나를 물린 두 가지 문제가 있습니다.
DateTime 해상도
Ticks 속성은 1 천만 분의 1 초 (100 나노초 블록) 단위로 시간을 측정하지만 해상도는 100 나노초가 아니라 약 15ms입니다.
이 코드는 :
long now = DateTime.Now.Ticks;
for (int i = 0; i < 10; i++)
{
System.Threading.Thread.Sleep(1);
Console.WriteLine(DateTime.Now.Ticks - now);
}
예를 들어 다음과 같이 출력됩니다.
0
0
0
0
0
0
0
156254
156254
156254
마찬가지로 DateTime.Now.Millisecond를 보면 15,625ms의 둥근 청크로 값을 얻을 수 있습니다 : 15, 31, 46 등
이 특정 동작은 시스템에 따라 다릅니다 만, 다른 해상도 관련 망 가지고있다 이 날짜 / 시간 API에가.
Path.Combine
파일 경로를 결합하는 좋은 방법이지만 항상 예상대로 작동하지는 않습니다.
두 번째 매개 변수가 \
문자로 시작 하면 완전한 경로를 제공하지 않습니다.
이 코드는 :
string prefix1 = "C:\\MyFolder\\MySubFolder";
string prefix2 = "C:\\MyFolder\\MySubFolder\\";
string suffix1 = "log\\";
string suffix2 = "\\log\\";
Console.WriteLine(Path.Combine(prefix1, suffix1));
Console.WriteLine(Path.Combine(prefix1, suffix2));
Console.WriteLine(Path.Combine(prefix2, suffix1));
Console.WriteLine(Path.Combine(prefix2, suffix2));
이 출력을 제공합니다.
C:\MyFolder\MySubFolder\log\
\log\
C:\MyFolder\MySubFolder\log\
\log\
콘솔에 쓰는 프로세스 (System.Diagnostics 사용)를 시작하지만 Console.Out 스트림을 읽지 않으면 일정량의 출력 후에 앱이 정지 된 것처럼 보입니다.
Linq-To-Sql에는 운영자 단축키가 없습니다.
간단히 말해서 Linq-To-Sql 쿼리의 조건절 내에서 null 참조 예외 ||
와 같은 조건부 바로 가기를 사용할 수 없습니다 &&
. Linq-To-Sql은 첫 번째 조건이 두 번째 조건을 평가할 필요가 없어도 OR 또는 AND 연산자의 양쪽을 평가합니다!
가상 메소드와 함께 기본 매개 변수 사용
abstract class Base
{
public virtual void foo(string s = "base") { Console.WriteLine("base " + s); }
}
class Derived : Base
{
public override void foo(string s = "derived") { Console.WriteLine("derived " + s); }
}
...
Base b = new Derived();
b.foo();
산출 :
파생 된 기초
변경 가능한 컬렉션의 값 개체
struct Point { ... }
List<Point> mypoints = ...;
mypoints[i].x = 10;
효과가 없습니다.
mypoints[i]
Point
값 객체 의 복사본을 반환 합니다. C #을 사용하면 복사본의 필드를 행복하게 수정할 수 있습니다. 조용히 아무것도하지 않습니다.
업데이트 : 이것은 C # 3.0에서 수정 된 것으로 보입니다.
Cannot modify the return value of 'System.Collections.Generic.List<Foo>.this[int]' because it is not a variable
아마도 최악은 아니지만 .net 프레임 워크의 일부 는 학위 를 사용 하는 반면 다른 일부는 라디안을 사용합니다 (Intellisense와 함께 제공되는 문서는 MSDN을 방문하여 찾을 필요가 없음)
Angle
대신 에 수업을 함으로써이 모든 것을 피할 수있었습니다 ...
C / C ++ 프로그래머에게는 C #으로의 전환이 당연합니다. 그러나 개인적으로 (그리고 다른 사람들과 같은 전환을 보았을 때) 가장 큰 어려움은 C #의 클래스와 구조체의 차이점을 완전히 이해하지 못한다는 것입니다.
C ++에서 클래스와 구조체는 동일합니다. 클래스는 기본적으로 비공개 가시성을 기본으로하고 기본적으로 공개 가시성을 기본으로하는 기본 가시성 만 다릅니다. C ++에서이 클래스 정의
class A
{
public:
int i;
};
이 구조체 정의와 기능적으로 같습니다.
struct A
{
int i;
};
그러나 C #에서 클래스는 참조 형식이고 구조체는 값 형식입니다. 이것은 (1) 다른 것을 사용할 때를 결정하는 것, (2) 객체의 동등성을 테스트하는 것, (3) 성능 (예 : 복싱 / 언 박싱) 등에서 큰 차이를 만듭니다 .
웹 (예 : here ) 의 차이점과 관련된 모든 종류의 정보가 웹에 있습니다 . 최소한 C #으로 전환하는 사람은 적어도 차이점과 그 의미에 대한 실무 지식을 갖도록 강력히 권장합니다.
가비지 콜렉션 및 Dispose (). 메모리 를 확보하기 위해 아무 것도 할 필요는 없지만 Dispose ()를 통해 리소스 를 확보 해야 합니다 . WinForms를 사용하거나 어떤 방식 으로든 객체를 추적 할 때 잊어 버리는 것은 매우 쉬운 일입니다.
foreach 루프 변수 범위!
var l = new List<Func<string>>();
var strings = new[] { "Lorem" , "ipsum", "dolor", "sit", "amet" };
foreach (var s in strings)
{
l.Add(() => s);
}
foreach (var a in l)
Console.WriteLine(a());
다섯 "amet"을 인쇄하고 다음 예제는 잘 작동합니다.
var l = new List<Func<string>>();
var strings = new[] { "Lorem" , "ipsum", "dolor", "sit", "amet" };
foreach (var s in strings)
{
var t = s;
l.Add(() => t);
}
foreach (var a in l)
Console.WriteLine(a());
MS SQL Server는 1753 년 이전의 날짜를 처리 할 수 없습니다. 중요한 것은 .NET DateTime.MinDate
상수 ( 1/1/1)와 동기화되지 않은 것입니다 . 따라서 마음에 들거나 잘못된 날짜 (최근에 데이터 가져 오기에서 발생 했음) 또는 정복자 윌리엄의 생년월일을 저장하려고하면 문제가 생길 수 있습니다. 이에 대한 기본 해결 방법은 없습니다. 1753 년 이전의 날짜로 작업해야 할 경우 자체 해결 방법을 작성해야합니다.
배열 구현 IList
그러나 그것을 구현하지 마십시오. 추가를 호출하면 작동하지 않는다는 메시지가 나타납니다. 그렇다면 왜 클래스가 인터페이스를 지원할 수 없을 때 인터페이스를 구현합니까?
컴파일하지만 작동하지 않습니다.
IList<int> myList = new int[] { 1, 2, 4 };
myList.Add(5);
serializer (WCF)가 모든 IList를 배열로 바꾸고 런타임 오류가 발생하기 때문에이 문제가 많이 있습니다.
불쾌한 Linq 캐싱 잡기
참조 내 질문 이 발견되었다 것을, 그리고 블로거 문제를 발견했다.
즉, DataContext는 사용자가로드 한 모든 Linq-to-Sql 오브젝트의 캐시를 유지합니다. 다른 사람이 이전에로드 한 레코드를 변경 하면 명시 적으로 레코드를 다시로드하더라도 최신 데이터를 얻을 수 없습니다 !
이는 ObjectTrackingEnabled
기본적으로 true 인 DataContext에서 호출 된 특성 때문입니다 . 해당 속성을 false로 설정하면 매번 레코드가 새로로드됩니다 ... 그러나 ... SubmitChanges ()를 사용하여 해당 레코드의 변경 내용을 유지할 수 없습니다.
고차!
Stream.Read의 계약 은 많은 사람들이 여행하는 것을 보았습니다.
// Read 8 bytes and turn them into a ulong
byte[] data = new byte[8];
stream.Read(data, 0, 8); // <-- WRONG!
ulong data = BitConverter.ToUInt64(data);
이 잘못된 이유는 즉 Stream.Read
읽을 대부분에서 지정된 바이트 수를하지만,이다 완전히 무료로 다른 7 바이트 스트림의 끝나기 전에 가능한 경우에도, 단지 1 바이트를 읽을 수 있습니다.
그것은 너무 비슷한이 보이는 것이 도움이되지 않습니다 Stream.Write
, 있다 가 없음을 제외하고 반환하는 경우 보장은 모든 바이트를 작성했습니다 수 있습니다. 또한 위의 코드 가 거의 항상 작동 하는 데 도움이되지 않습니다 . 물론 정확히 N 바이트를 정확하게 읽는 기성품, 편리한 방법이 없다는 것을 도움이되지 않습니다.
따라서 구멍을 막고 이에 대한 인식을 높이기 위해 올바른 방법의 예는 다음과 같습니다.
/// <summary>
/// Attempts to fill the buffer with the specified number of bytes from the
/// stream. If there are fewer bytes left in the stream than requested then
/// all available bytes will be read into the buffer.
/// </summary>
/// <param name="stream">Stream to read from.</param>
/// <param name="buffer">Buffer to write the bytes to.</param>
/// <param name="offset">Offset at which to write the first byte read from
/// the stream.</param>
/// <param name="length">Number of bytes to read from the stream.</param>
/// <returns>Number of bytes read from the stream into buffer. This may be
/// less than requested, but only if the stream ended before the
/// required number of bytes were read.</returns>
public static int FillBuffer(this Stream stream,
byte[] buffer, int offset, int length)
{
int totalRead = 0;
while (length > 0)
{
var read = stream.Read(buffer, offset, length);
if (read == 0)
return totalRead;
offset += read;
length -= read;
totalRead += read;
}
return totalRead;
}
/// <summary>
/// Attempts to read the specified number of bytes from the stream. If
/// there are fewer bytes left before the end of the stream, a shorter
/// (possibly empty) array is returned.
/// </summary>
/// <param name="stream">Stream to read from.</param>
/// <param name="length">Number of bytes to read from the stream.</param>
public static byte[] Read(this Stream stream, int length)
{
byte[] buf = new byte[length];
int read = stream.FillBuffer(buf, 0, length);
if (read < length)
Array.Resize(ref buf, read);
return buf;
}
행사
왜 이벤트가 언어 기능인지 이해하지 못했습니다. 그것들은 사용하기가 복잡합니다 : 당신은 전화하기 전에 null을 확인해야합니다, 당신은 (자신의) 등록을 취소해야합니다, 당신은 누가 등록되었는지 찾을 수 없습니다 (예 : 내가 등록 했습니까?) 도서관에서 이벤트가 수업이 아닌 이유는 무엇입니까? 기본적으로 전문 List<delegate>
?
오늘 나는 오랫동안 뛰어 다니지 않는 버그를 수정했습니다. 버그는 멀티 스레드 시나리오에서 사용되는 일반 클래스에 있었고 정적 int 필드를 사용하여 Interlocked를 사용하여 잠금 해제 동기화를 제공했습니다. 유형에 대한 일반 클래스의 각 인스턴스화에는 자체 정적이 있기 때문에 버그가 발생했습니다. 따라서 각 스레드에는 자체 정적 필드가 있으며 의도 한대로 잠금이 사용되지 않았습니다.
class SomeGeneric<T>
{
public static int i = 0;
}
class Test
{
public static void main(string[] args)
{
SomeGeneric<int>.i = 5;
SomeGeneric<string>.i = 10;
Console.WriteLine(SomeGeneric<int>.i);
Console.WriteLine(SomeGeneric<string>.i);
Console.WriteLine(SomeGeneric<int>.i);
}
}
이 인쇄 5 5 5
열거 가능 항목을 두 번 이상 평가할 수 있습니다
지연 열거 형 열거 형이 있고 두 번 반복하여 다른 결과를 얻을 때 물릴 것입니다. (또는 동일한 결과를 얻지 만 불필요하게 두 번 실행됩니다)
예를 들어, 특정 테스트를 작성하는 동안 로직을 테스트하기 위해 몇 개의 임시 파일이 필요했습니다.
var files = Enumerable.Range(0, 5)
.Select(i => Path.GetTempFileName());
foreach (var file in files)
File.WriteAllText(file, "HELLO WORLD!");
/* ... many lines of codes later ... */
foreach (var file in files)
File.Delete(file);
File.Delete(file)
던질 때 나의 놀람을 상상해보십시오 FileNotFound
!
여기서 일어나는 것은 files
열거 형이 두 번 반복되고 (첫 번째 반복의 결과는 단순히 기억 되지 않음 ) 각 새로운 반복에서 다시 호출 Path.GetTempFilename()
할 것이므로 다른 임시 파일 이름 세트를 얻게됩니다.
이 솔루션은 물론 사용하여 열망-열거 값이다 ToArray()
또는 ToList()
:
var files = Enumerable.Range(0, 5)
.Select(i => Path.GetTempFileName())
.ToArray();
다음과 같이 멀티 스레드 된 작업을 수행 할 때 더 무섭습니다.
foreach (var file in files)
content = content + File.ReadAllText(file);
그리고 당신 content.Length
은 모든 쓰기 후에도 여전히 0이라는 것을 알았습니다! 그런 다음 한 시간을 낭비한 후에도 경쟁 조건이 없는지 엄격하게 확인하기 시작합니다. 잊어 버린 작은 작은 열거 형 일뿐이라는 것을 알았습니다.
잠시 동안 디버그에 갇힌 이상한 것을 발견했습니다.
예외를 발생시키지 않고 nullable int에 대해 null을 증가시킬 수 있으며 값은 null로 유지됩니다.
int? i = null;
i++; // I would have expected an exception but runs fine and stays as null
TextInfo textInfo = Thread.CurrentThread.CurrentCulture.TextInfo;
textInfo.ToTitleCase("hello world!"); //Returns "Hello World!"
textInfo.ToTitleCase("hElLo WoRld!"); //Returns "Hello World!"
textInfo.ToTitleCase("Hello World!"); //Returns "Hello World!"
textInfo.ToTitleCase("HELLO WORLD!"); //Returns "HELLO WORLD!"
그렇습니다.이 동작은 문서화되었지만 확실하게 올바른 것은 아닙니다.
참고 URL : https://stackoverflow.com/questions/241134/what-is-the-worst-gotcha-in-c-sharp-or-net
'Programing' 카테고리의 다른 글
swift는 String에 트림 방법이 있습니까? (0) | 2020.02.26 |
---|---|
Swift의 URL에서 이미지로드 / 다운로드 (0) | 2020.02.26 |
16 진 숫자 앞에 0x가 붙는 이유는 무엇입니까? (0) | 2020.02.26 |
"java -server"와 "java -client"의 실제 차이점은 무엇입니까? (0) | 2020.02.26 |
Visual Studio에서 솔루션 및 디렉토리의 이름을 바꾸는 올바른 방법 (0) | 2020.02.26 |