Programing

C #의 문을 사용하여 중첩

lottogame 2020. 3. 18. 08:00
반응형

C #의 문을 사용하여 중첩


프로젝트를 진행 중입니다. 두 파일의 내용을 비교하여 서로 정확히 일치하는지 확인해야합니다.

많은 오류 확인 및 검증 전에 첫 번째 초안은 다음과 같습니다.

  DirectoryInfo di = new DirectoryInfo(Environment.CurrentDirectory + "\\TestArea\\");
  FileInfo[] files = di.GetFiles(filename + ".*");

  FileInfo outputFile = files.Where(f => f.Extension == ".out").Single<FileInfo>();
  FileInfo expectedFile = files.Where(f => f.Extension == ".exp").Single <FileInfo>();

  using (StreamReader outFile = new StreamReader(outputFile.OpenRead()))
  {
    using (StreamReader expFile = new StreamReader(expectedFile.OpenRead()))
    {
      while (!(outFile.EndOfStream || expFile.EndOfStream))
      {
        if (outFile.ReadLine() != expFile.ReadLine())
        {
          return false;
        }
      }
      return (outFile.EndOfStream && expFile.EndOfStream);
    }
  }

중첩 된 using진술 을하는 것이 조금 이상해 보입니다 .

더 좋은 방법이 있습니까?


이를 위해 선호되는 방법은 다음 과 같이 {마지막 using문장 뒤에 여는 중괄호 만 넣는 것입니다.

using (StreamReader outFile = new StreamReader(outputFile.OpenRead()))
using (StreamReader expFile = new StreamReader(expectedFile.OpenRead())) 
{
    ///...
}

객체의 유형같은 경우 다음을 수행 할 수 있습니다.

using (StreamReader outFile = new StreamReader(outputFile.OpenRead()), 
                    expFile = new StreamReader(expectedFile.OpenRead()))
{
    // ...
}

IDisposable유형이 동일한 경우 다음을 수행 할 수 있습니다.

 using (StreamReader outFile = new StreamReader(outputFile.OpenRead()), 
     expFile = new StreamReader(expectedFile.OpenRead()) {
     // ...
 }

MSDN 페이지 using의이 언어 기능에 대한 설명서가 있습니다.

IDisposable유형이 같은지 여부에 관계없이 다음을 수행 할 수 있습니다 .

using (StreamReader outFile = new StreamReader(outputFile.OpenRead()))
using (StreamWriter anotherFile = new StreamReader(anotherFile.OpenRead()))
{ 
     // ...
}

using 블록 앞에 using 블록에 대한 변수를 선언하는 것이 마음에 들지 않으면 모두 동일한 using 문으로 선언 할 수 있습니다.

    Test t; 
    Blah u;
    using (IDisposable x = (t = new Test()), y = (u = new Blah())) {
        // whatever...
    }

그렇게하면 x와 y는 using 블록에 사용할 IDisposable 유형의 자리 표시 자 변수 일 뿐이며 코드 내에서 t와 u를 사용합니다. 내가 언급 할 줄 알았는데


파일을 효율적으로 비교하려면 StreamReader를 전혀 사용하지 말고 사용하지 않아도됩니다. 낮은 수준의 스트림 읽기를 사용하여 비교할 데이터 버퍼를 가져올 수 있습니다.

또한 파일 크기와 같은 것을 먼저 비교하여 다른 파일을 빠르게 감지하여 모든 데이터를 읽을 필요가 없도록 할 수 있습니다.


using 문은 IDisposable 인터페이스에서 작동하므로 다른 옵션은 IDisposable을 구현하고 일반적으로 using 문에 넣을 모든 IDisposable 객체에 대한 참조를 갖는 복합 클래스 유형을 만드는 것입니다. 이것의 단점은 변수를 먼저 선언하고 범위 밖에서 변수를 선언해야 다른 제안 중 필요한 것보다 더 많은 코드 줄이 필요한 using 블록 내에서 변수가 유용하다는 것입니다.

Connection c = new ...; 
Transaction t = new ...;

using (new DisposableCollection(c, t))
{
   ...
}

이 경우 DisposableCollection의 생성자는 params 배열이므로 원하는만큼 입력 할 수 있습니다.


당신은 또한 말할 수 있습니다 :

using (StreamReader outFile = new StreamReader(outputFile.OpenRead()))
using (StreamReader expFile = new StreamReader(expectedFile.OpenRead()))
{
   ...
}

그러나 어떤 사람들은 그것을 읽기가 어려울 수 있습니다. BTW는 문제를 최적화하기 위해 한 줄씩 이동하기 전에 파일 크기가 같은 크기인지 먼저 확인하지 않는 이유는 무엇입니까?


여러 개의 일회용 객체를 하나의 using-statement로 쉼표로 그룹화 할 수 있습니다.

using (StreamReader outFile = new StreamReader(outputFile.OpenRead()), 
       expFile = new StreamReader(expectedFile.OpenRead()))
{

}

가장 안쪽을 제외하고 대괄호를 생략 할 수 있습니다.

using (StreamReader outFile = new StreamReader(outputFile.OpenRead()))
using (StreamReader expFile = new StreamReader(expectedFile.OpenRead()))
{
  while (!(outFile.EndOfStream || expFile.EndOfStream))
  {
    if (outFile.ReadLine() != expFile.ReadLine())
    {
      return false;
    }
  }
}

다른 사람들이 제안한 것처럼 동일한 유형의 여러 제품을 같은 용도로 사용하는 것보다 깨끗하다고 ​​생각하지만 많은 사람들이 이것이 혼란 스럽다고 생각할 것입니다


그것에 대해 이상한 것은 없습니다. using코드 블록이 완료되면 객체를 폐기하는 간단한 방법입니다. 내부 블록에 사용해야하는 일회용 블록이 외부 블록에있는 경우 이는 완벽하게 허용됩니다.

편집 : 통합 코드 예제를 표시하기 위해 입력 속도가 너무 느립니다. 다른 사람에게 +1


그리고 명확성을 더하기 위해이 경우 각 연속 명령문은 블록이 아닌 단일 명령문이므로 모든 괄호를 생략 할 수 있습니다.

using (StreamReader outFile = new StreamReader(outputFile.OpenRead()))
  using (StreamReader expFile = new StreamReader(expectedFile.OpenRead()))
    while (!(outFile.EndOfStream || expFile.EndOfStream))  
       if (outFile.ReadLine() != expFile.ReadLine())    
          return false;  

이것들은 내가 코딩 할 때 때때로 나타납니다. 두 번째 using 문을 다른 함수로 옮기는 것을 고려할 수 있습니까?


파일과 비교하는 더 좋은 방법이 있는지 묻고 있습니까? 두 파일 모두에 대해 CRC 또는 MD5를 계산하고 비교하는 것을 선호합니다.

예를 들어 다음 확장 방법을 사용할 수 있습니다.

public static class ByteArrayExtender
    {
        static ushort[] CRC16_TABLE =  { 
                      0X0000, 0XC0C1, 0XC181, 0X0140, 0XC301, 0X03C0, 0X0280, 0XC241, 
                      0XC601, 0X06C0, 0X0780, 0XC741, 0X0500, 0XC5C1, 0XC481, 0X0440, 
                      0XCC01, 0X0CC0, 0X0D80, 0XCD41, 0X0F00, 0XCFC1, 0XCE81, 0X0E40, 
                      0X0A00, 0XCAC1, 0XCB81, 0X0B40, 0XC901, 0X09C0, 0X0880, 0XC841, 
                      0XD801, 0X18C0, 0X1980, 0XD941, 0X1B00, 0XDBC1, 0XDA81, 0X1A40, 
                      0X1E00, 0XDEC1, 0XDF81, 0X1F40, 0XDD01, 0X1DC0, 0X1C80, 0XDC41, 
                      0X1400, 0XD4C1, 0XD581, 0X1540, 0XD701, 0X17C0, 0X1680, 0XD641, 
                      0XD201, 0X12C0, 0X1380, 0XD341, 0X1100, 0XD1C1, 0XD081, 0X1040, 
                      0XF001, 0X30C0, 0X3180, 0XF141, 0X3300, 0XF3C1, 0XF281, 0X3240, 
                      0X3600, 0XF6C1, 0XF781, 0X3740, 0XF501, 0X35C0, 0X3480, 0XF441, 
                      0X3C00, 0XFCC1, 0XFD81, 0X3D40, 0XFF01, 0X3FC0, 0X3E80, 0XFE41, 
                      0XFA01, 0X3AC0, 0X3B80, 0XFB41, 0X3900, 0XF9C1, 0XF881, 0X3840, 
                      0X2800, 0XE8C1, 0XE981, 0X2940, 0XEB01, 0X2BC0, 0X2A80, 0XEA41, 
                      0XEE01, 0X2EC0, 0X2F80, 0XEF41, 0X2D00, 0XEDC1, 0XEC81, 0X2C40, 
                      0XE401, 0X24C0, 0X2580, 0XE541, 0X2700, 0XE7C1, 0XE681, 0X2640, 
                      0X2200, 0XE2C1, 0XE381, 0X2340, 0XE101, 0X21C0, 0X2080, 0XE041, 
                      0XA001, 0X60C0, 0X6180, 0XA141, 0X6300, 0XA3C1, 0XA281, 0X6240, 
                      0X6600, 0XA6C1, 0XA781, 0X6740, 0XA501, 0X65C0, 0X6480, 0XA441, 
                      0X6C00, 0XACC1, 0XAD81, 0X6D40, 0XAF01, 0X6FC0, 0X6E80, 0XAE41, 
                      0XAA01, 0X6AC0, 0X6B80, 0XAB41, 0X6900, 0XA9C1, 0XA881, 0X6840, 
                      0X7800, 0XB8C1, 0XB981, 0X7940, 0XBB01, 0X7BC0, 0X7A80, 0XBA41, 
                      0XBE01, 0X7EC0, 0X7F80, 0XBF41, 0X7D00, 0XBDC1, 0XBC81, 0X7C40, 
                      0XB401, 0X74C0, 0X7580, 0XB541, 0X7700, 0XB7C1, 0XB681, 0X7640, 
                      0X7200, 0XB2C1, 0XB381, 0X7340, 0XB101, 0X71C0, 0X7080, 0XB041, 
                      0X5000, 0X90C1, 0X9181, 0X5140, 0X9301, 0X53C0, 0X5280, 0X9241, 
                      0X9601, 0X56C0, 0X5780, 0X9741, 0X5500, 0X95C1, 0X9481, 0X5440, 
                      0X9C01, 0X5CC0, 0X5D80, 0X9D41, 0X5F00, 0X9FC1, 0X9E81, 0X5E40, 
                      0X5A00, 0X9AC1, 0X9B81, 0X5B40, 0X9901, 0X59C0, 0X5880, 0X9841, 
                      0X8801, 0X48C0, 0X4980, 0X8941, 0X4B00, 0X8BC1, 0X8A81, 0X4A40, 
                      0X4E00, 0X8EC1, 0X8F81, 0X4F40, 0X8D01, 0X4DC0, 0X4C80, 0X8C41, 
                      0X4400, 0X84C1, 0X8581, 0X4540, 0X8701, 0X47C0, 0X4680, 0X8641, 
                      0X8201, 0X42C0, 0X4380, 0X8341, 0X4100, 0X81C1, 0X8081, 0X4040 };


        public static ushort CalculateCRC16(this byte[] source)
        {
            ushort crc = 0;

            for (int i = 0; i < source.Length; i++)
            {
                crc = (ushort)((crc >> 8) ^ CRC16_TABLE[(crc ^ (ushort)source[i]) & 0xFF]);
            }

            return crc;
        }

일단 파일을 비교하는 것은 매우 쉽습니다.

public bool filesAreEqual(string outFile, string expFile)
{
    var outFileBytes = File.ReadAllBytes(outFile);
    var expFileBytes = File.ReadAllBytes(expFile);

    return (outFileBytes.CalculateCRC16() == expFileBytes.CalculateCRC16());
}

내장 System.Security.Cryptography.MD5 클래스를 사용할 수 있지만 계산 된 해시는 바이트 []이므로 두 배열을 비교해야합니다.


또한 이미 경로를 알고 있다면 디렉토리를 스캔하는 것이 중요하지 않습니다.

대신 다음과 같은 것이 좋습니다.

string directory = Path.Combine(Environment.CurrentDirectory, @"TestArea\");

using (StreamReader outFile = File.OpenText(directory + filename + ".out"))
using (StreamReader expFile = File.OpenText(directory + filename + ".exp"))) 
{
    //...

Path.Combine 경로에 폴더 또는 파일 이름을 추가하고 경로와 이름 사이에 정확히 하나의 백 슬래시가 있는지 확인하십시오.

File.OpenText파일을 열고 한 번에 파일을 만듭니다 StreamReader.

@ 문자열을 접두어로하여 모든 백 슬래시를 탈출하는 것을 방지 할 수 있습니다 (예 @"a\b\c")


구문을 사용하여 구문을 명확하게 선언하는 방법을 찾았을 것 같습니다. 대신으로 IDisposable의 using 문에 형식이 보인다 VAR를 사용하여 동적으로 두 개체의 유형 추론과 내 객체 모두를 인스턴스화하고 같이 자신의 특성과 그들이 할당 된 클래스의 메소드를 호출 할 수 있습니다

using(var uow = new UnitOfWorkType1(), uow2 = new UnitOfWorkType2()){}.

사람이 이유를 알고 있다면 옳지 않다, 알려주세요


C # 8.0기다릴 수 있으면 using 선언을 사용할 수 있습니다 .

using var outFile = new StreamReader(outputFile.OpenRead());
using var expFile = new StreamReader(expectedFile.OpenRead());
while (!(outFile.EndOfStream || expFile.EndOfStream))
{
    if (outFile.ReadLine() != expFile.ReadLine())
    {
         return false;
    }
}
return (outFile.EndOfStream && expFile.EndOfStream);

일반적인 사용법이며 완벽하게 작동합니다. 이것을 구현하는 다른 방법이 있지만. 거의 모든 답변이이 질문의 답변에 이미 존재합니다. 그러나 여기에 나는 그것들을 모두 함께 나열하고 있습니다.

이미 사용 된

using (StreamReader outFile = new StreamReader(outputFile.OpenRead()))
  {
    using (StreamReader expFile = new StreamReader(expectedFile.OpenRead()))
    {
      while (!(outFile.EndOfStream || expFile.EndOfStream))
      {
        if (outFile.ReadLine() != expFile.ReadLine())
        return false;
      }
    }
  }

옵션 1

using (StreamReader outFile = new StreamReader(outputFile.OpenRead()))
    using (StreamReader expFile = new StreamReader(expectedFile.OpenRead()))
    {
      while (!(outFile.EndOfStream || expFile.EndOfStream))
      {
        if (outFile.ReadLine() != expFile.ReadLine())
        return false;
      }
    }
  }

옵션 2

using (StreamReader outFile = new StreamReader(outputFile.OpenRead()),
                    expFile = new StreamReader(expectedFile.OpenRead()))
   {
      while (!(outFile.EndOfStream || expFile.EndOfStream))
       {
         if (outFile.ReadLine() != expFile.ReadLine())
         return false;
       }
    }

참고 URL : https://stackoverflow.com/questions/1329739/nested-using-statements-in-c-sharp

반응형