본문스크랩 인덱서


C# 클래스가 인덱서를 선언하여 클래스에 대한 배열형 액세스를 제공하는 방법을 보여 줍니다.

 

설명

인덱서를 정의하면 "가상 배열"처럼 동작하는 클래스를 만들 수 있습니다. 해당 클래스의 인스턴스는[]배열 액세스 연산자를 사용하여 액세스할 수 있습니다. C#에서 인덱서를 정의하는 것은 C++에서[]연산자를 정의하는 것과 유사하지만 훨씬 더 융통성이 있습니다. 배열형이나 컬렉션형 기능을 캡슐화하는 클래스에 대해 인덱서를 사용하면 해당 클래스의 사용자가 배열 구문을 사용하여 클래스에 액세스할 수 있습니다.

예를 들어, 파일을 바이트 배열로 표시하는 클래스를 정의한다고 가정해 봅시다. 파일이 너무 크면 약간의 바이트만 읽거나 변경하려는 경우에는 특히 전체 파일을 메모리로 읽어 들일 수 없습니다. FileByteArray 클래스를 정의하면 바이트 배열과 유사하게 파일을 표시할 수 있지만 실제로는 바이트을 읽거나 쓸 때 파일 입력과 출력을 실행합니다.

다음 예제 외에도 이 자습서에서는 인덱싱된 속성 만들기에 대한 고급 항목에 대해 설명합니다.

 

예제

다음 예제에서는 FileByteArray 클래스를 사용하여 바이트 배열처럼 파일에 액세스할 수 있습니다. Reverse 클래스는 파일 바이트의 순서를 반대로 바꿉니다. 이 프로그램을 실행하여 프로그램 원본 파일을 포함하는 모든 텍스트 파일의 바이트 순서를 바꿀 수 있습니다. 바이트 순서가 바뀐 파일을 다시 일반 파일로 변경하려면 같은 파일에서 프로그램을 다시 실행해야 합니다.

// indexer.cs
// arguments: indexer.txt
using System;
using System.IO;

// Class to provide access to a large file
// as if it were a byte array.
public class FileByteArray
{
    Stream stream;      // Holds the underlying stream
                        // used to access the file.
// Create a new FileByteArray encapsulating a particular file.
    public FileByteArray(string fileName)
    {
        stream = new FileStream(fileName, FileMode.Open);
    }

    // Close the stream. This should be the last thing done
    // when you are finished.
    public void Close()
    {
        stream.Close();
        stream = null;
    }

    // Indexer to provide read/write access to the file.
    public byte this[long index]   // long is a 64-bit integer
    {
        // Read one byte at offset index and return it.
        get
        {
            byte[] buffer = new byte[1];
            stream.Seek(index, SeekOrigin.Begin);
            stream.Read(buffer, 0, 1);
            return buffer[0];
        }
        // Write one byte at offset index and return it.
        set
        {
            byte[] buffer = new byte[1] {value};
            stream.Seek(index, SeekOrigin.Begin);
            stream.Write(buffer, 0, 1);
        }
    }

    // Get the total length of the file.
    public long Length
    {
        get
        {
            return stream.Seek(0, SeekOrigin.End);
        }
    }
}

// Demonstrate the FileByteArray class.
// Reverses the bytes in a file.
public class Reverse
{
    public static void Main(String[] args)
    {
        // Check for arguments.
        if (args.Length == 0)
        {
            Console.WriteLine("indexer <filename>");
            return;
        }

        FileByteArray file = new FileByteArray(args[0]);
        long len = file.Length;

        // Swap bytes in the file to reverse it.
        for (long i = 0; i < len / 2; ++i)
        {
            byte t;

            // Note that indexing the "file" variable invokes the
            // indexer on the FileByteStream class, which reads
            // and writes the bytes in the file.
            t = file[i];
            file[i] = file[len – i – 1];
            file[len – i – 1] = t;
        }

        file.Close();
    }
}

 

다음과 같은 내용이 들어 있는 텍스트 파일을 사용하여 프로그램을 테스트할 수 있습니다.

Test.txt 파일 로 저장하셔야 합니다. (cs파일 아님)

public class Hello1
{
   public static void Main()
   {
      System.Console.WriteLine("Hello, World!");
   }
}

이 파일의 바이트 순서를 바꾸려면 프로그램을 컴파일한 다음 다음과 같은 명령줄을 사용해야 합니다.

indexer Test.txt

바이트 순서가 바뀐 파일을 표시하려면 다음과 같은 명령을 입력해야 합니다.

Type Test.txt

또는 직접 열어보세요!

출력 (Test.txt)

}
}
;)"!dlroW ,olleH"(eniLetirW.elosnoC.metsyS
{
)(niaM diov citats cilbup
{
1olleH ssalc cilbup

 

코드 설명

  • 인덱서는[]연산자를 사용하여 액세스되므로 이름이 없습니다.
  • 위 예제에서 인덱서는 형식 바이트이며 long(64비트 정수) 형식의 단일 인덱스를 사용합니다. Get 접근자는 파일에서 바이트를 읽을 코드를 정의하며 Set 접근자는 파일에 바이트를 쓸 코드를 정의합니다. Set 접근자에서 미리 정의된 매개 변수 값에는 가상 배열 요소에 할당된 값이 들어 있습니다.
  • 인덱서에는 적어도 한 개의 매개 변수가 있어야 합니다. 드문 경우이지만 인덱서에 다차원 "가상 배열"을 시뮬레이션하기 위한 둘 이상의 매개 변수가 있을 수도 있습니다. 정수 매개 변수가 가장 일반적이지만 모든 형식의 인덱서 매개 변수가 가능합니다. 예를 들어, 표준 Dictionary 클래스는 Object 형식의 매개 변수를 인덱서에 제공합니다.
  • 인덱서가 강력한 기능이기는 하지만 배열형 추상화가 가능할 때만 사용하는 것이 좋습니다. 일반 메서드를 사용하는 것이 타당한지 항상 고려해야 합니다. 예를 들어 다음은 인덱서의 잘못된 사용 예입니다.
  • class Employee
    {
        // VERY BAD STYLE: using an indexer to access
        // the salary of an employee.
        public double this[int year]
       {
            get
            {
                // return employee’s salary for a given year.
            }
       }
    }

    잘못된 것은 아니지만 인덱서에 Get 접근자만 있는 경우는 바람직하지 않습니다. 이러한 경우에는 메서드 사용을 심각하게 고려해야 합니다.

  • 인덱서는 오버로드될 수 있습니다.
  •  

     

     


    답글 남기기

    이메일 주소는 공개되지 않습니다.