프로그래밍

인터페이스와 확장메서드의 활용

기본적으로 다중 상속을 지원하지 않는 C#의 디자인때문에 인터페이스 상속을 이용해 다중상속을 구현해왔습니다. 이와 관련한 내용으로 오래전부터 포스팅해야 겠다는 생각만 했을 뿐 실천을 하지 못하던 중 여유가 생겨 정리해 봅니다.

인터페이스 선언

RegisterFrm

위 코드에서 보듯 Java와 마찬가지로 C# 역시 여러 클래스를 동시에 상속할 수 없습니다. 따라서 Java와 동일한 방법으로 인터페이스를 이용하여 이러한 결과를 얻을 수는 있습니다. 하지만 인터페이스는 메서드 시그니쳐가 포함되어있을 뿐 구현이 포함되어있지 않습니다. 인터페이스는 상수, 필드, 생성자, 소멸자, 모든 형식의 정적멤버를 포함할 수 없습니다.

따라서 C#에서 여러개의 클래스를 상속하고자 한다면 반드시 인터페이스를 이용해야 하고, 그 구현부는 상속받은 클래스에서 구현되어야 합니다.

인터페이스 사용

FiscalizacionDetailBase

이 예에서는 보여드리는 클래스인 FiscalizacionDetailBase라는 클래스는 전자결제를 사용하기 위해 IElectronicApproval을 상속하고 있습니다. 하지만 또다른 RegisterFrm이라는 클래스는 이력관리를 위한 IHistoryManagement를 상속하고 있습니다. 모두 같은 FormBase라는 슈퍼클래스를 상속하고 있습니다.

따라서 각 기능에 해상하는 상속을 구현하기 위해(=다중 상속을 이용하기 위해) 각기 다른 인터페이스를 상속받고 있습니다.

하지만 C# 3.0부터 지원하는 확장 메서드를 이용한다면 무척 편리하게 구현이 가능합니다. (물론 개발자 입장에서 구현의 편리함을 강조하는 것입니다.)

이 예에서는 전자결제에서 사용하고자 하는 매개변수들과 이력관리에서 사용하는 매개변수가 다릅니다. 때문에 해당 인터페이스에 해당하는 구현부를 각각의 클래스들에서 구현했었어야 합니다. 물론 객제지향개발 방법론에 의하면 올바른 구현이 아닙니다.

이를 OOP의 가르침대로 구현하려면 먼저 FormBase가 각 인터페이스를 상속하고, FormBase에서 인터페이스를 구현했었어야 합니다. 그 이후 FormBase를 상속하는 클래스에서는 필요한 인터페이스를 상속하여 구현된 시그내처를 사용하는 것입니다. 그러나 이렇게 구현을 했을 경우 지나치게 FormBase가 무거워질 수 있습니다. 사용하지 않는 불필요한 구현부가 있기 때문이지요. OOP에 대해 이야기 한다는것 자체가 꽤 진부하니 OOP이야기는 여기서 마무리하지요.

이야기하고 있는 인터페이스는 다음과 같이 디자인 했습니다.

   1:      public interface IElectronicApproval : IHistoryManagement
   2:      {
   3:          Enum.ButtonMode eButtonMode { get; set; }
   4:          string BizDocType { get; }
   5:          string CurrentSaveFlag { get; set; }
   6:          string CurrentStatusCode { get; set; }
   7:          decimal CurrentVersion { get; set; }
   8:          string HoldingResult { get; set; }
   9:          string ExistResult { get; set; }
  10:          string ScreenName { get; set; }
  11:          string Language { get; set; }
  12:      }

   1:      public interface IHistoryManagement
   2:      {
   3:          Enum.UIMode eUIMode { get; set; }
   4:  
   5:          string RegisterCode { get; set; }
   6:          string RegisterLocation { get; set; }
   7:          string UpdaterCode { get; set; }
   8:          string UpdaterLocation { get; set; }
   9:          DateTime RegisterDate { get; set; }
  10:          DateTime UpdateDate { get; set; }
  11:          DateTime EffectiveDate { get; set; }
  12:      }

보다시피 각 인터페이스는 메서드 시그내쳐는 없습니다. 다만 프로퍼티들만 존재할 뿐입니다.

이에 필요한 메서드는 확장메서드를 이용해 구현합니다. 다음과 같이 말이죠.

   1:          public static void SetApprovalRequiredParameter(this IElectronicApproval electronicApproval, RequestParameter rParam)
   2:          {
   3:              rParam.Add("BizDocType", electronicApproval.BizDocType);
   4:              rParam.Add("SaveFlag", ((ushort)electronicApproval.eButtonMode).ToString());
   5:  
   6:              rParam.Add("CurrentSaveFlag", electronicApproval.CurrentSaveFlag);
   7:              rParam.Add("CurrentStatusCode", electronicApproval.CurrentStatusCode);
   8:              rParam.Add("CurrentStatusCode1", GetStatusCode1(electronicApproval.CurrentStatusCode));
   9:              rParam.Add("CurrentStatusCode2", GetStatusCode2(electronicApproval.CurrentStatusCode));
  10:              rParam.Add("CurrentVersion", electronicApproval.CurrentVersion);
  11:  
  12:              rParam.Add("Language", SetNullAsValue(electronicApproval.Language, Session.LANGUAGE));
  13:  
  14:              electronicApproval.SetHistoryRequiredParameter(rParam);
  15:          }

이렇게 구현한 확장메서드를 상속받은 클래스에서는 다음과 같이 이용합니다.

SetApprovalRequiredParameter(rParam);

이와 같이 인터페이스의 메서드 시그니쳐를 확장메서드를 이용해 구현하여 사용하는 방법도 있습니다.

VS SP1없이 SQL 2008 설치하기

SQL 2008 설치시 Visual Studio 2008 Sp1은 사전 요구사항입니다. sp1없이 설치할 수 있는 트릭이 있기에 소개해봅니다. 물론, Visual Studio 2008은 있어야 합니다. sp1을 무시한채 설치하는 방법이죠.

sql previous releases of visual studio 2008 sp1 setup.exe

Rule “Previous releases of Microsoft Visual Studio 2008″ failed.

두 가지의 방법이 있으니 사용하시기 편한 방법으로 사용해 보세요.

1. Command의 옵션을 통해 규칙을 무시할 수 있습니다.

Setup /ACTION=install /SkipRules=VSShellInstalledRule RebootRequiredCheck

2. 레지스트리를 수정해 Visual Studio 2008이 설치되어 있지 않은 것처럼 속이는 방법입니다.

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DevDiv\VS\Servicing\9.0

“9.0″을 임의로 수정해 놓으면 됩니다.

이러한 방법으로 SQL 2008 사용시 SQL 2008의 모든 기능을 자유롭게 사용할 수 있을지는 모르겠습니다. 아직까지 개발환경에서 위 방법으로 여러개의 인스턴스를 만들어 사용하고 있습니다만 딱히 문제가 될 부분은 없는 듯 합니다.

관련 링크.

http://blogs.msdn.com/psssql/archive/2008/08/11/sql-server-2008-visual-studio-2008-sp1-and-net-framework-3-5-sp1-explained.aspx

http://hyok.kr/blog/dev/44?category=12

CLR Injection 관련 링크.

.NET의 고급기술중의 하나로,  CLR Injection과 관련한 링크를 모으고 있습니다. 이 글은 계속 갱신됩니다.

 

CLR Injection: Runtime Method Replacer
http://www.codeproject.com/KB/dotnet/CLRMethodInjection.aspx

.NET Internals and Code Injection
http://www.ntcore.com/Files/netint_injection.htm

SOS Debugging Extension
http://msdn.microsoft.com/en-us/library/bb190764.aspx

SOS Cheat Sheat
http://geekswithblogs.net/.NETonMyMind/archive/2006/03/14/72262.aspx

Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects
http://msdn.microsoft.com/en-us/magazine/cc163791.aspx

Digging into interface calls in the .NET Framework: Stub-based dispatch
http://blogs.msdn.com/vancem/archive/2006/03/13/550529.aspx

Debugging Rotor Jit Call
http://www.xwang.org/2009/02/debugging-rotor-jit-call/

ARM Jazelle DBX (Direct Bytecode eXecution)
http://www.arm.com/products/multimedia/java/jazelle.html

SQL Server 2008 Desinger Behavior Change : Saving Changes Not Permitted

SQL Management Studio 2008을 사용하고 있습니다.

Management Studio 2008

Management Studio 2008

테이블의 변경이 발생했을 경우 SMS2008의 테이블 디자이너에서는 변경내역이 저장되지 않는 문제가 있었습니다. 아래와 같은 경고 메시지를 보여주면서요.

Saving changes is not permitted. The changes you have made require the following tables to be dropped and re-created. You have either made changes to a table that can’t be re-created or enabled the option Prevent saving changes that require the table to be re-created.

또한 사용자에게 ‘Cancel’과 ‘Save Text File’이라는 버튼만 보여준 채 ‘Cancel’을 클릭하면 사용자가 변경을 취소했다는 메시지를 보여줍니다. 취소하고 싶어서, 취소를 누른건 아니잖아요…?

Management Studio 2008

Management Studio 2008

이는 SQL Server 2008 Books Online (March 2009)에서 확인할 수 있었는데요.

  • 테이블의 중간에 새로운 컬럼이 추가되는 경우.
  • 컬럼을 삭제하는 경우.
  • 컬럼의 nullability를 변경하는 경우.
  • 컬럼의 순서를 변경하는 경우.
  • 컬럼의 타입을 변경하는 경우.

위 다섯 가지에 해당 되는 테이블의 변경사항은 SMS2008의 테이블 디자이너에서는 변경할 수 없었습니다. SQL서버는 테이블이 삭제되었고,  이미 만들어진 테이블을 삭제하고, 다시 생성해야 하기 때문이라고 합니다. 2008에서는 테이블의 변경에 대해 경각심을 주겠다는 의도로 옵션을 만들어두어 기본값은 재생성을 할 수 없도록 하지 않았나 생각해 봅니다. 물론 ALTER [TABLE]과 같은 DDL을 사용한다면 아무런 제약이 없습니다.

이러한 문제를 해결하기 위해서 다음과 같이 조취합니다.

메뉴에서 도구 -> 옵션 -> 디자이너를 선택합니다. ‘Prevent saving changes that require table re-creation’의 체크를 해제하면 SMS2008에서 테이블 디자인의 변경이 가능해집니다.

Management Studio 2008

Tools -> Options -> Designers

Management Studio 2008

'Prevent saving changes that require table re-creation'의 체크를 해제합니다.

DataTable로 Select Top 구현하기..

원칙대로라면 쿼리를 통해 Top절을 구현해야 함이 마땅하지만 비즈니스를 구현하다보면 종종 이미 가져온 DataTable에서 Top절을 구현하는 것이 현명할 때가 있다.  

실제로 DataTable에서 Distinct절도 구현해야 할 경우가 종종 있으니 말이다. 지금은 LINQ를 이용하면 좀 더 쉽겠지만 현재 진행중인 프로젝트에서 LINQ는 개발표준에 없으므로 LINQ절을 사용할 수 없다.

따라서, 아래와 같은 코드로 DataTable의 Select Top절을 구현해 보았다.

   1:  public DataTable GetSelectTop(DataTable sourceTable, int topCount)
   2:  {
   3:      try
   4:      {
   5:          DataView dvTable = sourceTable.DefaultView;
   6:          dvTable.Sort = "Total_Size DESC";
   7:   
   8:          DataTable destTable = sourceTable.Clone();
   9:          topCount = dvTable.Count > topCount ? dvTable.Count : topCount;
  10:   
  11:          for (int i = 0; i < topCount; i++)
  12:          {
  13:              DataRow row = dvTable[i].Row;
  14:              destTable.ImportRow(dv);
  15:          }
  16:          return destTable;
  17:      }
  18:   
  19:      catch (Exception e)
  20:      {
  21:          throw e;
  22:      }
  23:  }