나는 몇 가지 코너 케이스와 뇌 맛보기를 수집하고 항상 더 많은 것을 듣고 싶습니다. 이 페이지는 실제로 C # 언어 비트와 밥을 다루지 만 핵심 .NET 항목도 흥미 롭습니다. 예를 들어, 여기 페이지에 없지만 믿을 수없는 것을 발견했습니다.
string x = new string(new char[0]);
string y = new string(new char[0]);
Console.WriteLine(object.ReferenceEquals(x, y));
False를 인쇄 할 것으로 예상됩니다-결국 “새”(참조 유형) 항상 새 개체를 생성합니까? C #과 CLI 모두에 대한 사양에 따라야합니다. 글쎄,이 특별한 경우에는 그렇지 않습니다. True를 인쇄하고 테스트 한 모든 버전의 프레임 워크에서 수행했습니다. (필자는 분명히 모노에서 시도하지 않았습니다 …)
분명히, 이것은 내가 찾고있는 종류의 예일뿐입니다-나는이 이상한 점에 대한 토론 / 설명을 특별히 찾지 않았습니다. (일반 문자열 인턴과 동일하지 않습니다. 특히 문자열 인턴은 생성자가 호출 될 때 일반적으로 발생하지 않습니다.) 실제로 비슷한 이상한 동작을 요구했습니다.
다른 보석이 숨어 있습니까?
답변
나는 당신에게 이것을 이전에 보여줬다 고 생각하지만, 나는 여기서 재미를 좋아합니다-이것은 추적하기 위해 약간의 디버깅이 필요했습니다! (원래 코드는 분명히 더 복잡하고 미묘했습니다 …)
static void Foo<T>() where T : new()
{
T t = new T();
Console.WriteLine(t.ToString()); // works fine
Console.WriteLine(t.GetHashCode()); // works fine
Console.WriteLine(t.Equals(t)); // works fine
// so it looks like an object and smells like an object...
// but this throws a NullReferenceException...
Console.WriteLine(t.GetType());
}
그래서 T는 …
답변 : 어떤 Nullable<T>
– 등 int?
. GetType ()을 제외한 모든 메서드는 재정의됩니다. 따라서 null을 호출하는 object.GetType () …을 호출하기 위해 객체로 캐스팅 (따라서 null로)됩니다.
업데이트 : 줄거리가 두껍게 … Ayende Rahien은 자신의 블로그 에서 비슷한 도전을 던졌지 만 where T : class, new()
:
private static void Main() {
CanThisHappen<MyFunnyType>();
}
public static void CanThisHappen<T>() where T : class, new() {
var instance = new T(); // new() on a ref-type; should be non-null, then
Debug.Assert(instance != null, "How did we break the CLR?");
}
그러나 이길 수 있습니다! 원격과 같은 것들에 의해 사용 된 것과 같은 간접적 사용; 경고-다음은 순수한 악입니다 .
class MyFunnyProxyAttribute : ProxyAttribute {
public override MarshalByRefObject CreateInstance(Type serverType) {
return null;
}
}
[MyFunnyProxy]
class MyFunnyType : ContextBoundObject { }
이를 사용하면 new()
호출이 프록시 ( MyFunnyProxyAttribute
)로 리디렉션되어을 반환합니다 null
. 자 가서 눈을 씻으십시오!
답변
은행가의 반올림.
이것은 컴파일러 버그 나 오작동이 아니라 이상한 코너 케이스입니다 …
.Net Framework는 Banker ‘s Rounding으로 알려진 구성표 또는 반올림을 사용합니다.
은행원 반올림에서 0.5 숫자는 가장 가까운 짝수로 반올림되므로
Math.Round(-0.5) == 0
Math.Round(0.5) == 0
Math.Round(1.5) == 2
Math.Round(2.5) == 2
etc...
이로 인해 잘 알려진 Round-Half-Up 반올림을 기반으로 재무 계산에서 예기치 않은 버그가 발생할 수 있습니다.
Visual Basic에서도 마찬가지입니다.
답변
이 함수는 Rec(0)
(디버거가 아닌)으로 호출되면 어떻게됩니까?
static void Rec(int i)
{
Console.WriteLine(i);
if (i < int.MaxValue)
{
Rec(i + 1);
}
}
대답:
- 32 비트 JIT에서는 StackOverflowException이 발생합니다.
- 64 비트 JIT에서는 모든 숫자를 int.MaxValue에 인쇄해야합니다.
때문입니다 64 비트 JIT 컴파일러는 꼬리 호출 최적화를 적용 32 비트 JIT하지 않는 반면,.
불행히도 이것을 검증 할 64 비트 머신이 없지만 메소드는 테일 콜 최적화를위한 모든 조건을 충족합니다. 아무도 가지고 있지 않다면 나는 그것이 사실인지 알고 싶습니다.
답변
이것을 할당하십시오!
이것은 내가 파티에서 묻고 싶은 것입니다 (아마도 더 이상 초대받지 않는 이유 일 것입니다).
다음 코드를 컴파일 할 수 있습니까?
public void Foo()
{
this = new Teaser();
}
쉬운 속임수는 다음과 같습니다.
string cheat = @"
public void Foo()
{
this = new Teaser();
}
";
그러나 실제 해결책은 다음과 같습니다.
public struct Teaser
{
public void Foo()
{
this = new Teaser();
}
}
따라서 값 유형 (구조체)이 this
변수를 재 할당 할 수 있다는 사실은 알지 못합니다 .
답변
몇 년 전, 충성도 프로그램을 진행할 때 고객에게 제공되는 포인트의 양에 문제가있었습니다. 이 문제는 double을 int로 캐스팅 / 변환하는 것과 관련이 있습니다.
아래 코드에서 :
double d = 13.6;
int i1 = Convert.ToInt32(d);
int i2 = (int)d;
i1 == i2 입니까?
i1! = i2로 밝혀졌습니다. 변환 및 캐스트 연산자에서 다른 반올림 정책으로 인해 실제 값은 다음과 같습니다.
i1 == 14
i2 == 13
항상 Math.Ceiling () 또는 Math.Floor () 또는 요구 사항을 충족하는 MidpointRounding을 사용하는 Math.Round를 호출하는 것이 좋습니다.
int i1 = Convert.ToInt32( Math.Ceiling(d) );
int i2 = (int) Math.Ceiling(d);
답변
열거 형 함수 과부하가 있어도 0을 정수로 만들어야합니다.
0을 열거 형에 매핑하는 C # 핵심 팀의 이론적 근거를 알고 있었지만 여전히 직교하지는 않습니다. Npgsql의 예 .
테스트 예 :
namespace Craft
{
enum Symbol { Alpha = 1, Beta = 2, Gamma = 3, Delta = 4 };
class Mate
{
static void Main(string[] args)
{
JustTest(Symbol.Alpha); // enum
JustTest(0); // why enum
JustTest((int)0); // why still enum
int i = 0;
JustTest(Convert.ToInt32(0)); // have to use Convert.ToInt32 to convince the compiler to make the call site use the object version
JustTest(i); // it's ok from down here and below
JustTest(1);
JustTest("string");
JustTest(Guid.NewGuid());
JustTest(new DataTable());
Console.ReadLine();
}
static void JustTest(Symbol a)
{
Console.WriteLine("Enum");
}
static void JustTest(object o)
{
Console.WriteLine("Object");
}
}
}
답변
이것은 내가 지금까지 본 것 중 가장 특이한 것 중 하나입니다 (물론 여기에서 제외하십시오!) :
public class Turtle<T> where T : Turtle<T>
{
}
그것은 당신이 그것을 선언 할 수는 있지만 실제 사용하지는 않습니다. 왜냐하면 그것은 항상 당신이 다른 클래스로 센터에있는 클래스를 포장하도록 요구하기 때문입니다.
[농담] 거북이가 끝까지 내려간 것 같아 … [/ 농담]