IT 이모저모

C # 역방향 레시피 - 1

exien 2018. 3. 6. 17:39

제 04 장 문 및 특수 연산자

060 중첩 루프에서 벗어나고 싶다

goto 문

 goto 문은 지정된 라벨 (끝에 ":"로 끝낸 식별자)에 제어를 옮깁니다. 유명한 goto 유해 론 (NOTE를 참조하십시오)의 goto와 유사한 기능입니다. 그러나 가도록 지정 지정 레이블은 변수의 가시성 규칙에 따릅니다. 즉, 블록 내부와 메소드를 걸쳐 레이블을 지정할 수 없습니다.

NOTE : goto 문 시비

 현대는 마치 "구단 (반인 소 요괴) '처럼 실제로 사용되고있는 코드를 본 적도 없는데 싫어 두려워하는 사람이 존재하는 것이 흥미로운 점이다.

 goto를 사용하지 않고 다중 루프를 나가게 상태 변수를 도입하여 복잡한 if 문 및 다수의 break를 작성한다면 하나의 goto를 작성해야합니다.

x, y, z 3 개의 루프 내부에서의 탈출
 for ( var x = 1 ; x < 100 ; x ++) { for ( var y = 1 ; y < 100 ; y ++) { for ( var z = 1 ; z < 100 ; z ++) { // x의 제곱이 3y + 5z과 동일하게되면 처리를 종료한다 if ( Math . Pow ( x , 2 ) == 3 *   
 
     
  
      
   
    
         y + 5 * z ) { Console . WriteLine ( $ "x ^ 2 == 3 * y + 5 * z; x = {x} y = {y}, z = {z}" ); goto found ; / / 라벨 끝에 ":"쓰지 않는다 } } } } Console . WriteLine ( "unknown" ); // 끝까지 루프를 달리면 찾을 수없는 것이다 
found : // 레이블 식별자 + ":"로 기술 하는 Console . WriteLine ( "end" );  
    
     
      
    
   
  
 
   
 

"나 자신은 루프가 깊어지지 않도록 메서드에 분할하기 때문에 goto를 사용할 기회는 거의 없지만, 다중 루프에서 탈출 if와 break를 각층에 둔 더러운 코드는 눈에합니다. 그런 코드를 보면 goto를 사용하는 편이 좋은데하네요 "

제 08 장 클래스

160 이상의 값을 반환하는 메서드를 만들려면 (Tuple을 사용하고)

Tuple 클래스를 이용하는

 Tuple 클래스를 사용하면 클래스 나 구조체를 정의하지 않고 유형 정보와 함께 여러 값을 하나의 객체로 취급합니다. 예를 들어 컬렉션에 저장 메서드 인수, 반환 값 등입니다. Tuple은 여러 형태와 값의 조합을 운반하는 간이 객체에서 Tuple.Create 정적 메소드를 사용하여 만듭니다.

Tuple은

 Tuple (튜플)은 쌍 (2 개 세트), 세 쌍둥이 (3 쌍) 등을 일반화 한 '쌍'에서하고 구성 요소의 순서화가 정해져있는 것을 말합니다. 예를 들어, 본 레시피 샘플은 Item1과 Item2는 다른 의미를 가지므로 순서가 중요하며, tuple을 사용할 수 있습니다.

여러 값을 반환하는 메서드의 반환에 Tuple을 이용하는
using System ; class Calc { // 2 개의 int를 저장하는 Tuple을 돌려 준다. Tuple에는 형식 매개 변수 <>이 필수 static Tuple 
 

 
   Div ( int x , int y ) { // Item1에 상, Item2에 나머지를 유지하는 Tuple을 생성하는 return Tuple . Create ( x / y , x % y ); } static void Main () { var result = Div ( 81 , 13 ); // 나눗셈의 몫과 나머지를 표시하는 // Tuple이 포함 된 개체로는 Item1, Item2 ...... 속성에 액세스 할 Console . WriteLine ( $ "81 / 13 = {result.Item1}. .. {result.Item2} " 
 
  
   
 
   
 
    
  
  
  ); } } // 출력 // 81 / 13 = 6 ... 3
 


"Tuple 유용하지만, 의외로 구현이 깨끗하지 않을군요.하지만 유용한 것 일수록 빨리 변화 해 나가는 것이 C # 좋은 곳이므로 점점 다듬어 나갈 것입니다. 모처럼 올렸다 이렇게 빨리 오래 될 것 같은 슬픈 이지만요 "

제 11 장 파일 제어

204 안전한 파일의 업데이트 방법을 알고 싶어요

안전한 파일의 업데이트는

 중요한 파일은 프로그램의 버그 디스크 전체를 포함한 실행시 디스크 장애, 처리 대상 데이터의 이상 등에 의한 손실이나 파괴 된 데이터 만 남아있는 것을 방지해야합니다.

 안전하게 파일을 업데이트하려면 다음 단계를 취합니다.

  1. 업데이트 할 파일을 읽기 전용으로 열기
  2. 업데이트 된 파일을 쓰기 위해 열
  3. 업데이트 (2)의 파일에 대해 수행 (갱신 처리는 (1)에서 (2)에 대한 업데이트 처리를 수반하는 필터링 처리한다)
  4. (1) 파일을 백업용으로 이름을 변경
  5. (3) 처리가 완료된 파일을 (1) 파일로 대체

 이렇게하면 디스크에 필요한 공간은 일시적으로 원본 파일의 두 배 이상이됩니다 만, 어느 시점에서 장애가 발생해도 업데이트 이전의 파일을 복원 할 수 있습니다.

File.Replace 정적 메소드를 이용하면

 File 클래스의 Replace 정적 메서드는 동일한 디스크 드라이브에있는 파일에 대해 위의 (4) ~ (5)의 단계를 수행합니다.

// 업데이트 용 파일은 임시 파일로 var info = new FileInfo ( Path . GetTempFileName ( )); try { // 갱신 대상 파일을 읽기 전용으로 오픈하는 using ( var reader = File . OpenText ( args [ 0 ]) ) // 갱신 대상 파일을 쓰기 위해 열 수 using ( var writer = File . CreateText ( info . FullName )) { var line = string .
    


 
   
 
   
 
    Empty ; while (( line = reader . ReadLine ( )) ! = null ) { // 업데이트 작업을 수행 
    writer . WriteLine ( line . Replace ( "vb" , "cs" )); } } // File.Replace은 // 첫번째 파라미터로 지정한 파일을 // 두번째 파라미터로 지정한 파일로 대체 // 제 3 인수로 지정된 파일에 원래의 제 2 인수로 지정된 파일은 백업되는 File . Replace ( info . FullName , args [ 0 ] Path
        
   
     
   
  
 
 
 
 
  . ChangeExtension ( args [ 0 ] ".backup" )); } finally { // 성공하면 File.Replace 메소드에 의해 삭제 (이동) 된이 될 
 info . Delete ( ); }



   

"File.Replace의 발상은 좋습니다만, 다른 드라이브의 파일을 취급 할 수없는 점에서 아쉬운 메소드입니다. 처음에는 File.Replace 정적 메소드를 사용하지 않는 방법으로 생각했지만 오래되어 버리므로 사용 로했습니다. 물론 같은 드라이브 밖에 사용할 수 없다라고 기재 해 두었습니다. 모두 같은 드라이브에서 실행하는 디스크 장애에 대하여 안전하지 않은 것입니다 만, 거기에 눈을 감 으면 뜻이 높은 메소드가 있습니다 (웃음) "

제 14 장 LINQ

232 NameValueCollection을 LINQ에서 사용하고자

컬렉션에 LINQ를 적용 할 수없는 경우는 IEnumerable <T>을 만들

 NameValueCollection와 그 파생 클래스는 구형의 컬렉션 (IEnumerable)이므로 LINQ를 적용 할 수 없습니다.

 이런 경우 다음과 같이 IEnumerable <T>를 만듭니다.

  1. Keys (또는 AllKeys) 속성 확장 메서드 Cast <T>를 키의 형태를 지정하여 적용합니다.
  2. Cast 메서드가 반환 IEnumerable <T>의 Select 메서드를 호출합니다. Select에 미치는 람다 식의 인수에 주어진 키를 원래 NameValueCollection에 적용하여 값을 가져오고 키와 값 쌍을 포함하는 익명 클래스 또는 튜플을 반환합니다.
  3. (2)에 의해 키와 값 쌍의 IEnumerable <T>를 얻을 수 있으므로, 이후에는 정상적으로 LINQ에서 설명합니다.
WebResponse의 Headers 속성 (WebHeaderCollection)에 LINQ에 액세스 할
// using System.Net;가 필요 // URI를주고 HttpWebRequest를 생성 var req = WebRequest . CreateHttp ( "http://example.com/" ); 
req . UserAgent = "testagent" ; 
req . Accept = "* / *" ; // Web 서버에서 응답을 얻을 using ( var resp = req . GetResponse ()) { // WebResponse.Headers은 WebHeaderCollection이므로 그대로는 LINQ를 적용 할 수없는 // Cast <string>을 호출 키 의 IEnumerable <string>을 얻을 foreach ( var h

     

 

 
 
  in resp . Headers . Keys . Cast <string> () // Select를 호출하여 키와 값의 익명 클래스의 객체로 변환 . Select ( k => new { Key = k , Values = resp . Headers . GetValues ( k ) }) // 키에 Content를 포함하는 것을 추출하기 . Where ( kv => kv . Key . IndexOf ( "Content" ) > = 0 ))
  
         
  
    
 { // Values는 string [] 그래서 string.Join를 사용하여 모든 요소를 출력하는 Console . WriteLine ( $ "{h.Key} : {string.Join (" , ", h.Values)}" ); } } // 출력 (예) // Content-Length : 1270 // Content-Type : text / html
  
  
 



"전부 LINQ에 쓰고 싶은데 레거시 컬렉션에 LINQ에서 쓸 수없는 것이 있고 싫다는 아는 사람이있었습니다. 이것은 처음 내가 다가 오지 않았다지만, 잠시 후"왜 LINQ에서 사용할 수없는 거지? "라고 실제로 느낄 수 몇 번 있었기 때문에 레시피로 게재하기로했습니다. 덧붙여서, LINQ를 SQL처럼 쓰는 것은 실용성 전무의 단순한 데모 목적이라고 생각하고 있기 때문에 전문 프로그래머를위한 책에서는 소개하지 않습니다 "

제 15 장 네트워크와 통신

247 IP 주소와 MAC 주소를 원한다

취득 절차

IP 주소와 MAC 주소는 컴퓨터의 네트워크 인터페이스 (가상을 포함하는 네트워크 어댑터)에 따라 달라집니다.

 이를 이용하여 다음과 같이 IP 주소와 MAC 주소를 가져옵니다.

  1. System.Net.NetworkInformation.NetworkInterface 클래스의 GetAllNetworkInterfaces 정적 메소드를 호출합니다.
  2. (1)이 반환 NetworkInterface 객체의 배열의 각 요소에 대해 다음을 수행합니다. 이때 NetworkInterfaceType 속성이 System.Net.NetworkInformation.NetworkInterfaceType 열거 형의 Ethernet 이외의 것은 무시합니다.
  3. GetIPProperties 메서드를 호출 System.Net.NetworkInformation.IPInterfaceProperties 개체를 가져옵니다.
  4. a. IPv4 주소가 필요한 경우 IPInterfaceProperties 개체 GetIPv4Properties 메소드를 호출합니다. null가 아니면 IPv4의 정보를 보유하고 있기 때문에 UnicastAddresses 속성 (System.Net.NetworkInformation.UnicastIPAddressInformation 클래스의 컬렉션)을 열거합니다. 
     b. IPv6 주소가 필요한 경우 IPInterfaceProperties 개체 GetIPv6Properties 메소드를 호출합니다. null가 아니면 IPv4의 정보를 보유하고 있기 때문에 UnicastAddresses 속성 (System.Net.NetworkInformation.UnicastIPAddressInformation 클래스의 컬렉션)을 열거합니다.
  5. UnicastIPAddressInformation 개체의 Address 속성을 참조 System.Net.IPAddress 클래스의 객체를 가져옵니다.
  6. IPAddress 객체의 AddressFamily 속성을 참조합니다. System.Net.Sockets.AddressFamily 열거 형이 돌아가므로, IPv4 주소가 필요한 경우 AddressFamily.InterNetwork 것을 IPv6 주소가 필요한 경우 AddressFamily.InterNetworkV6 것을 선택합니다.
  7. (6)에서 선택한 IPAddress 개체의 ToString 메서드를 호출하여 읽을 수있는 표현을 구하십시오.
  8. MAC 주소를 얻으려면, (4) a. 또는 (4) b.에서 선택된 NetworkInterface 객체를 이용합니다. 
     a. GetPhysicalAddress 메서드를 호출 System.Net.NetworkInformation.PhysicalAddress 개체를 가져옵니다. 
     b. PhysicalAddress 개체의 ToString 메서드를 호출하여 읽을 수있는 표현을 구하십시오.
컴퓨터에서 사용 가능한 IPv4 및 IPv6 주소를 표시하는
// using System.Net.NetworkInformation; using System.Net.Sockets;가 필요 // 모든 네트워크 어댑터를 열거 foreach ( var intf in NetworkInterface . GetAllNetworkInterfaces () // 이더넷 유형의 것만을 선택 . Where ( itf => itf . NetworkInterfaceType == NetworkInterfaceType . Ethernet ) // 후속 처리가 편해지도록 필요한 정보 만 개체를 만들 . Select ( itf => new { Name = itf . Name , MacAddress =

  
 
   
 
     
                       itf . GetPhysicalAddress () IPProperties = itf . GetIPProperties () }) // IP 주소를 가질 지 어떨지를 판정 // GetIPv? Properties는 각각 반환 형식이 다르기 때문에 본래는 ??는 연결할 수없는 // 여기에서는 null 여부의 판정이므로 object에 캐스팅 동시에 판정하고있다 . Where ( e => (( object ) e . IPProperties . GetIPv4Properties () ?? ( object ) e . IPProperties . GetIPv6Properties ()) ! = null )) {
                        
 
 
 
  
              

 // 어댑터 이름과 MAC 주소를 출력하는 Console . WriteLine ( $ "Name : {intf.Name} MACAddress : {BitConverter.
 
ToString (intf.MacAddress.GetAddressBytes ())} " ); // IPv4 주소를 표시하는 foreach ( var address in intf . IPProperties . UnicastAddresses . Select ( e => e . Address ) . Where ( e => e . AddressFamily == AddressFamily . InterNetwork )) { Console . WriteLine ( $ "IPv4 address : {address}" ); } // IPv6 주소를 표시하는
 
  
  
    
 
  
 
 
 foreach ( var address in intf . IPProperties . UnicastAddresses . Select ( e => e . Address ) . Where ( e => e . AddressFamily == AddressFamily . InterNetworkV6 )) { Console . WriteLine ( $ "IPv6 Address : {address}" ); } } // 출력 // Name : vEthernet (Hyper-V virtual interface), MACAddress : 00-xx-xx-xx-xx-xx 
  
    
 
  
 



// IPv4 Address : 192.168.253.10 // IPv6 Address : xxxx : xxxx : xxxx : xxxx : xxxx % yy
GetUnicastAddresses 메소드를 이용하는 방법

 .NET Framework 4 이상이면 다음 프로그램과 같이 사용 가능한 UnicastAddressInformation 컬렉션을 System.Net.NetworkInformation.IPGlobalProperties 클래스의 GetUnicastAddresses 메소드로 취득 할 수 있습니다. 어댑터 정보 등이 불필요한 경우에는이 방법이 간편합니다.

사용 가능한 IPv4 주소 가져 오기 (.NET Framework 4 이상)
// using System.Net.NetworkInformation; using System.Net.Sockets;가 필요 var address = IPGlobalProperties . GetIPGlobalProperties () . GetUnicastAddresses () // 이후의 처리에 IPAddress 객체의 // 열거로 변환 . Select ( e => e . Address ) // IPv4 여기에서는 제한 (IPv6 주소가 // 필요하다면 조건을 바꾸는) . Where ( e => e . AddressFamily == AddressFamily . InterNetwork ) //이 방법은 루프백 주소 (127.0.0.1)가 // 포함되므로 제외
 
  
  
  
  
  
  
    
  
  
  . Where ( e => ! IPAddress . IsLoopback ( e )) // 멀티 홈 컴퓨터의 경우 다른 조건도 필요 고려 . First (); Console . WriteLine ( $ "IPv4 Address : {address}" ); 
  
  

"이것은 역작입니다. 어렵게 샘플 코드를 작성 했습니다만, 소개하고있는대로 .NET Framework 4에서 짧은 코드로 이루어진다거든요 ..NET Flamework에서 자주 사용하는 기능은 점점 변화하고 가므로, 제대로 잡을 가지 않으면 매우 손해를합니다. 새로운 것을 기억 짧게 쓰는 것이 유리한 것인가, 지금 알고 긴 코드를 이전의 소스에서 복사 - 붙여 넣기 해 오는 것이 에너지 절약인지 판단 는 어렵지만, 어딘가에서 새로운 업데이트 해 나가지 않으면 C #과 교제하고있는만큼 앞으로도 그 예전의 코드를 사용하여 버리니까요. 정신을 차려 보니 지식도 코드도 업데이트 해 갑시다 "