잊지 않겠습니다.

'.NET Gotcha'에 해당되는 글 3건

  1. 2009.01.07 Chapter 3. Language and API Gotchas
  2. 2009.01.07 Chapter 2. Visual Studio and Complier Gotchas
  3. 2009.01.07 Chapter 1. CLR/Framework Gotchas

Singleton is't guaranteed process-wide

Singletone으로 만들어주는 static method의 경우에는 Process에 귀속되지 않는다.

.NET에서는 Singleton은 AppDomain에 유일한 존재로 staic 을 생성하게 된다.

   

Default performance of Data.ReadXML is poor

ReadXML의 경우에는 xsd 파일이 지정되어있지 않는 경우에는 매우 속도가 느리게 된다.

Data.ReadXML을 사용하는 경우에는 반드시 xsd 파일을 지정해줘야지 된다.

   

enum lacks type-safety

enum 형태는 int 형태에 의미를 부여할 수 있는 형태로, 사용이 매우 편한 형태이지만, int의 casting을 시켜줄때는 type-safety가 이루어지지 않기 때문에 사용에 주의를 해줘야지 된다.

   

Copy constructor hampers exensibility

Constructor에서 다른 객체의 copy를 만드는 형태의 경우에는 모든 객체의 값들을 같이 참조하는 형태로 만들어지게 된다. 따라서 하나의 객체의 값이 바뀌게 되면, 다른 객체의 값까지 바뀌게 되는 형태로 만들어지기 때문에 피하는 것이 좋다.

이러한 copy constructor의 문제는 C++, Java, .NET에서 모두 같이 발생하는 문제가 된다.

   

Clon() has limitations

"copy constructor hampers exensibility"와 동일한 문제가 발생한다.

MemberwiseClone()의 경우에도 역시 마찬가지로, 같은 문제가 발생하기 때문에, 두개의 각각 다른 id를 갖지만 같은 객체의 값을 갖는 copy본을 만들어주고 싶을 때는 주의가 필요하다.

   

Object initialization sequence isn't consistent

C#과 VB.NET에서의 Initialization sequence가 각각 다르다.

Base Class에서 someClass1을 선언과 동시에 초기화 시키고, Base Class를 상속받는 Derived Class가 someClass2를 선언과 동시에 초기화 시킬때,

C#
  1. someClass2 초기화
  2. someClass1 초기화
  3. BaseClass 초기화
  4. DerivedClass 초기화
VB.NET
  1. someClass1 초기화
  2. BaseClass 초기화
  3. someClass2 초기화
  4. DerivedClass 초기화

  

Polymorphism kicks in prematurely

Constructor에서 override가 될 수 있는 virtual 함수의 호출은 하지 않는다.

virtual 함수의 호출을 Constructor에서 시켜줄 경우에는 Derived Class에서의 초기화는 항시 Base Class의 virtual 함수를 호출하게 된다. override 된 자신의 함수를 호출하는 형태가 될 수 없다.

Posted by Y2K
,

Complier warning may not be benign

Compiler에서의 경고를 무시하지 말아라. Compiler에서의 경고는 모두다 없애는 것이 가장 우선되는 일이 된다.

Treat warnings as errors option을 활성화시키고 나서 compile하는 것이 좋다.

모든 project의 수행시에, 이 옵션을 활성화 시키고 나서 시작하는 것이 유용하다.

   

Ordering of catch processin isn't consist across languages

try~catch 구문에서 C#과 VB.NET의 동작 방법은 다르다.

C#에서는 위에서부터 아래로 넘어갈 수록, 범위가 낮은 exception class로 넘어가게 되지만, VB.NET에서는 exception class로 바로 jump 하게 된다.

static void Main(string[] args)
{
 try
 {
  AMethod();
 }
 catch(Exception ex)
 {
  Console.WriteLine(ex.Message);
 }
 catch(ApplicationException ex)
 {
  Console.WriteLine(ex.Message); <- 절대 수행될 수 없다.
 }
}

   

Type.GetType() might fail at run-time

Type.GetType() 보다는 typeof/GetType를 주로 사용하는 것이 좋다.

   

rethrow isn't consistent

catch(Exception ex)으로 잡힌 error를 throw ex로 해서 다시 던지게 될 경우에는 exception안의 정보를 잃어버릴 수 있다. 이럴때는 catch(Exception)에서 throw로 다시 던져주거나, throw ex.InnerException을 이용해서 Exception을 보내주는 것이 좋다.

   

Versioning may lead to Serialization headaches

: 이미 Serialization된 객체에 대해서 객체의 또다른 member 변수등의 변경이 생겼을 때에, 기존의 serialization의 데이터를 불러오는 데에 문제가 생기게 된다. 이때에, exception을 사용해서 하는 방법도 있으나, 가장 좋은 것은 아래 코드와 같이 Helper를 이용해서 객체의 데이터를 Type의 이름에 따라 얻어오는 방법이다.

  public class SerializationHelper
  {
    /// <summary>
    /// Desirialization이 될때에, 호출을 시켜서 새로 생성되는 객체에 값을 채워주는 함수.
    /// 각각을 enumerator에서 MoveNext로 움직이는 것으로 모든 객체의 값을 얻어온다.
    /// 만약에 구버젼의 Serialization 객체인 경우에는 그 값이 없기 때문에 채워지지 않고,
    /// 기본 값을 얻어오게 된다.
    /// </summary>
    /// <param name="theType"></param>
    /// <param name="instance"></param>
    /// <param name="info"></param>
    public static void SetData(Type theType, Object instance, SerializationInfo info)
    {
      SerializationInfoEnumerator enumerator = info.GetEnumerator();

      while(enumerator.MoveNext())
      {
        string fieldName = enumerator.Current.Name;
        FieldInfo theField =
          theType.GetField(fieldName,
                           BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public |
                           BindingFlags.NonPublic);

        if ( theField != null )
        {
          theField.SetValue(instance, enumerator.Value);
        }
      }
    }

    /// <summary>
    /// Serialization이 될 때에 불러지는 함수
    /// Instance의 모든 값들을 얻어와서 Serialization을 행한다.
    /// </summary>
    /// <param name="theType"></param>
    /// <param name="instance"></param>
    /// <param name="info"></param>
    public static void GetData(Type theType, Object instance, SerializationInfo info)
    {
      FieldInfo[] fields =
        theType.GetFields(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public |
                          BindingFlags.NonPublic);

      foreach(FieldInfo fieldInfo in fields)
      {
        if(!fieldInfo.IsNotSerialized)
        {
          info.AddValue(fieldInfo.Name, fieldInfo.GetValue(instance));
        }
      }
    }
  }

  

Create Web apps can be painful

blank solution을 만들어 준 후에, 그 안에 project를 만들어주는 것이 project를 만들어주는 것으로 시작하는 것보다 더 낫다.

  • 디자인 된 solution에 원하는 project를 넣는 것이 가능하다. (source의 src, test의 구분이 더 쉬워진다.)
  • 여러 solution에 결합되어 있는 project들의 관리가 보다 용의하다.

IIS에서 virtual directory를 미리 만들어두고, 웹사이트를 만들어주고, 개발을 행하는 것이 훨신더 편한 방법으로 web site의 개발이 가능해진다.

  

Naming XML documentation for IntelliSense support isn't intuitive

XML-style documentation으로 만들어진 code에 대한 xml format은 자동적으로 Visual studio의 intellisense에서 사용되어질 수 잇다. 그렇지만, 하나의 제약으로 가질수 있는 것이, assembly name과 xml file의 이름을 동일하게 해줄 필요가 있다. 자동적으로 찾지는 못한다.

Posted by Y2K
,

The Common Language Runtime(CLR) provides a common platform for the execution of programs in .NET.

.NET language is first translated into the Microsoft Intermediate Language(MSIL).

   

Type alias size doesn't match what you're familiar with

Common Language Specification(CLS)의 특징

  • cross-language integration
  • type safety
  • high-performance execution of managed code

WinAPI의 DllImport 시에 Type 값은 서로간에 byte size를 맞춰줄 필요가 있다.

   

Structure and Class differ in behavior

  • class(reference type) : be created on the heap
  • structure(value type) : be created on the stack

   

Returning value types from a method/property is risky

: Value type으로 return을 받을 경우와 Reference type으로 return을 받을 때, 동작을 유의해야지 된다.

DateTime dtDate = DateTime.Now; <- value type

dtDate.AddDate(1) <- dtDate 값은 변화하지 않음.

   

You can't force calls to your value-type constructors

  • value-type constructor에서 일반 생성자를 호출하는 것은 불가능하다.
  • 값의 초기화를 초기값(int :0, boolean : false) 이외에 값으로 초기화 하는 것이 불가능하다.

   

String concatenation is expensive

  • string에서 string의 모음에서 +를 이용하는 것보다, StringBuilder.Append()를 이용해서 string을 모으는 것이 좋다.
  • 1000000번 '.'를 결합할때, +를 사용하는 경우에는 3562.933 sec가 소요되며, StringBuilder를 사용하는 경우에는 0.07sec의 시간이 소요된다.

   

Exceptions may go unhandled

  • Windows app에서는 Application.ThreadException을 handling 시켜주고, Console app에서는 AppDomain.CurrentDomain.UnhandledException을 handling 시켜줘서 사용해준다.
  • 사용자에게 넘겨주는 모든 error를 사용자에게 넘기지 않고, 내부에서 처리가 되어야지 된다.

   

Uninitialized event handlers aren't treated gracefully

Delegate 된 event의 경우에는 연결되지 않을 경우에는 null reference error가 발생한다.

모든 Event를 동작할 때는 반드시 event의 null point error를 check를 해주는 것이 필요하다.

   

Division operation isn't consistent between types

  • 0로 나뉠때 나오는 에러인 DivisionByZeroException이 나올때, double로 나누어질 때는 eps또는 (+-) 무한대로 나타날 수 있기 때문에, DivisionByZeroException이 나타나지 않을 수 있다.
  • 0로 나뉘어지는 것이 우려될 때는 , IsInfinity() method를 호출해서 값의 형태를 확인해봐야지 된다.

   

Typeless ArrayList isn't type-safe

 System.Collections.ArrayList에서는 모든 데이터가 reference type으로 들어가는 것이 가능하지만, 그 값은 type 변환에 안전하지 못하다.

주의해서 사용하거나, System.Generic을 이용해서 type-safe로 만들어주는 것이 좋다.

  

Type.GetType() may not locate all types

선언되어 있는 class library에서 여러개의 중복된 이름을 가질 수 있기 때문에, 하나의 이름만으로 모든 것을 다 얻어내는 것은 불가능하다. 이때에는 reference type name과 version, public key를 모두 적어줘야지 인식시킬 수 있다.

  

Public key reported by sn.exe is inconsistent

"sn.exe -k"로 key를 만들어줄때는 각 key는 private key만이 갖고 있다. public key는 private key에 pair로 만들어서 서명하는 형식으로 만들어줘야지 된다. Visual Studio 2000에서는 "sn.exe -t" 옵션이 잘못 동작하고 있었다. (구버젼을 사용하는 경우에 주의 할것)

Posted by Y2K
,