728x90

Visual Studio 패키지 관리자 콘솔

Install-Package Spire.Doc -Version 8.10.4

 

using추가

using Spire.Doc;

메소드 정의

 public static string[] GetDocxPlainText(string _filePath)
        {
            //Create word document
            Document document = new Document();

            //load a document
            document.LoadFromFile(_filePath);

            string plainText = document.GetText();
            string[] splitLine = plainText.Split(new[] { "\r\n" }, StringSplitOptions.None);

            return splitLine;
        }

 

'Study > C#' 카테고리의 다른 글

c#트랙바를 통한 볼륨 조절  (0) 2017.05.18
IP 주소 정수로 변환  (0) 2017.05.16
C# Thread  (0) 2017.04.24
C# MS-SQL 연동  (0) 2017.04.14
C# 네트워크 기본  (1) 2017.04.12
728x90

사운드 관련 클래스 정의

using System.Runtime.InteropServices;
public class Win32
        {
            #region 사운드 관련
            [DllImport("winmm.dll")]
            public static extern int waveOutGetVolume(IntPtr hwo, out uint dwVolume);
 
            [DllImport("winmm.dll")]
            public static extern int waveOutSetVolume(IntPtr hwo, uint dwVolume);
 
            public static void SetSoundVolume(int volume)
            {
                try
                {
                    int newVolume = ((ushort.MaxValue / 10* volume);
                    uint newVolumeAllChannels = (((uint)newVolume & 0x0000ffff| ((uint)newVolume << 16));
                    waveOutSetVolume(IntPtr.Zero, newVolumeAllChannels);
                }
                catch (Exception) { }
            }
 
            public static int GetSoundVolume()
            {
                int value = 0;
                try
                {
                    uint CurrVol = 0;
                    waveOutGetVolume(IntPtr.Zero, out CurrVol);
                    ushort CalcVol = (ushort)(CurrVol & 0x0000ffff);
                    value = CalcVol / (ushort.MaxValue / 10);
                }
                catch (Exception) { }
                return value;
            }
            #endregion
        }



폼의 생성자

public Form1()
        {
            InitializeComponent();
            formInit();
 
            lobbyBgm.PlayLooping();
            Win32.SetSoundVolume(5);    // 초기 볼륨 설정 (0~10)
 
            trackBar1.Value = Win32.GetSoundVolume();   // 트랙바의 값을 현재 볼륨값으로 설정
        }


트랙바 스크롤 이벤트

private void trackBar1_Scroll(object sender, EventArgs e)
        {
            int volume;
            volume = trackBar1.Value;
            
            Win32.SetSoundVolume(volume);
        }


'Study > C#' 카테고리의 다른 글

c# docx 에서 텍스트 얻기  (0) 2020.10.28
IP 주소 정수로 변환  (0) 2017.05.16
C# Thread  (0) 2017.04.24
C# MS-SQL 연동  (0) 2017.04.14
C# 네트워크 기본  (1) 2017.04.12
728x90
public string BringIP()
        {
            IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
            string ip = string.Empty;
 
            for (int i = 0; i < host.AddressList.Length; i++)
                if (host.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
                    ip = host.AddressList[i].ToString();
 
            return ip;
        }
      
 
        public Form1()
        {
            InitializeComponent();
            
            byte[] ip = BringIP().Split('.').Select(s => Byte.Parse(s)).ToArray();
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(ip);
            }
            uint num = BitConverter.ToUInt32(ip, 0);
 
            txtServerIP.Text = num.ToString();
        }


'Study > C#' 카테고리의 다른 글

c# docx 에서 텍스트 얻기  (0) 2020.10.28
c#트랙바를 통한 볼륨 조절  (0) 2017.05.18
C# Thread  (0) 2017.04.24
C# MS-SQL 연동  (0) 2017.04.14
C# 네트워크 기본  (1) 2017.04.12
728x90

Thread 관련 예제


using System;
using System.Threading;
 
namespace Study_CS_ConsoleApp
{
    class Program
    {
        static Thread threadA = new Thread(FuncA);
        static Thread threadB = new Thread(FuncB);
        static Thread threadC = new Thread(FuncC);
 
 
        static void FuncA()
        {
 
            for(int i=0; i<50; i++)
            {
                if (i > 30)
                    threadA.Abort();
 
                Console.WriteLine("A : Count = " + i);
            }
        }
 
        static void FuncB()
        {
            for (int i=0; i<50; i++)
            {
                System.Threading.Thread.Sleep(100);
                Console.WriteLine("B : Count = " + i);
            }
        }
 
        static void FuncC()
        {
            for (int i = 0; i < 50; i++)
            {   
                Console.WriteLine("C : Count = " + i);
                threadC.Suspend();
            }
        }
 
        static void Main(string[] args)
        {
            threadA.Start();
            threadB.Start();
            threadC.Start();
        }
    }
}



suspend()와 resume()


using System;
using System.Threading;
 
namespace Study_CS_ConsoleApp
{
    class Program
    {
        static Thread threadA = new Thread(FuncA);
        static Thread threadB = new Thread(FuncB);
        
        static void FuncA()
        {
 
            for(int i=0; i<=10; i++)
            {
                System.Threading.Thread.Sleep(100);
                Console.WriteLine("A : Count = " + i);
 
                if(i == 0)  // 조건문이 없으면 또 다시 Suspend
                threadA.Suspend();
            }
        }
 
        static void FuncB()
        {
            for (int i=0; i<=10; i++)
            {
                System.Threading.Thread.Sleep(100);
                Console.WriteLine("B : Count = " + i);
            }
            threadA.Resume();
        }
 
        static void Main(string[] args)
        {   
            threadA.Start();
            threadB.Start();
        }
    }
}


delegate


using System;
using System.Threading;
 
namespace Study_CS_ConsoleApp
{
    class Program
    {
        // 델리게이트 선언
        public delegate int cal(int a, int b);
 
        public static int Plus(int a, int b) { return a + b; }
        public static int Minus(int a, int b) { return a - b; }
 
        static void Main(string[] args)
        {
            cal plus = new cal(Plus);
            cal minus = new cal(Minus);
 
            Console.WriteLine(plus(46));
            Console.WriteLine(minus(115));
        }
    }
}



'Study > C#' 카테고리의 다른 글

c#트랙바를 통한 볼륨 조절  (0) 2017.05.18
IP 주소 정수로 변환  (0) 2017.05.16
C# MS-SQL 연동  (0) 2017.04.14
C# 네트워크 기본  (1) 2017.04.12
C# 예외처리, delegate  (0) 2017.04.10
728x90


using System;
using System.Data.SqlClient;
 
namespace CS_ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            SqlConnection con = new SqlConnection();
            //SqlCommand cmd = new SqlCommand();
            Console.WriteLine("연결시도");
 
            con.ConnectionString = "server=210.119.12.79,1617; database=ADO; uid=sa; pwd=it17";
 
            con.Open();
            SqlCommand cmd = new SqlCommand("SELECT * FROM ADO", con);
 
            Console.WriteLine("DB 연결 성공");
 
            /*
            Console.WriteLine("테이블 만들기 시도");
            cmd.Connection = con;
            cmd.CommandText = "CREATE table 성적표 (" +
                "번호 int primary key," +
                "이름 varchar(6) not null," +
                "국어 int," +
                "영어 int," +
                "수학 int)";
            
 
            cmd.ExecuteNonQuery();
            Console.WriteLine("테이블 만들기 성공");
            */
 
            Console.WriteLine("데이터 추가 시도");
            cmd.CommandText = "INSERT INTO 성적표 VALUES(1, '추경호', 95, 100, 85)";
            cmd.ExecuteNonQuery();
 
            cmd.CommandText = "INSERT INTO 성적표 VALUES(2, '조수현', 100, 80, 85)";
            cmd.ExecuteNonQuery();
            con.Close();
        }
    }
}



using System;
using System.Data.SqlClient;
 
namespace CS_ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            SqlConnection con = new SqlConnection();
            Console.WriteLine("DB 연결시도");
            con.ConnectionString = "server=210.119.12.79,1617; database=ADO; uid=sa; pwd=it4321";
            con.Open();
            Console.WriteLine("DB 연결 성공");
 
            SqlCommand cmd = new SqlCommand(); 
            
            cmd.Connection = con;
 
            Display(cmd);
 
            cmd.CommandText = "update 성적표 set 영어=@영어,수학=@수학 " +
                "where 이름='조수현'";
            cmd.Parameters.AddWithValue("@영어"99);
            cmd.Parameters.AddWithValue("@수학"88);
            cmd.ExecuteNonQuery();
            Display(cmd);
 
            cmd.CommandText = "DELETE FROM 성적표 WHERE 이름 = @이름";
            cmd.Parameters.AddWithValue("@이름""조수현");
            cmd.ExecuteNonQuery();
            Display(cmd);
 
            con.Close();
        }
 
        static void Display(SqlCommand cmd)
        {
            SqlDataReader sqlReader = null;
            cmd.CommandText = "select * from 성적표";
            sqlReader = cmd.ExecuteReader();
 
            for (int i = 0; i < sqlReader.FieldCount; i++)
            {
                Console.Write("{0,7}", sqlReader.GetName(i));
            }
            Console.WriteLine();
 
            string field = "";
            while (sqlReader.Read())
            {
                for (int i = 0; i < sqlReader.FieldCount; i++)
                {
                    field = sqlReader.GetName(i);
                    Console.Write("{0,8}", sqlReader[field]);
                }
                Console.WriteLine();
            }
            sqlReader.Close();
        }
    }
}



윈폼


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace DB3
{
    public partial class Form1 : Form
    {
        SqlConnection con;
        SqlDataAdapter mSqlDataAdapter;
        DataSet mDataSet;
        DataTable mDataTable;
 
        public Form1()
        {
            InitializeComponent();
 
            try
            {
                if (con == null)
                    con = new SqlConnection();
 
                textBox1.AppendText("DB연결 시도\r\n");
                con.ConnectionString =
                "server=PKNU1\\SQLEXPRESS;database=ADO;uid=sa;pwd=1234";
                con.Open();
                textBox1.AppendText("DB연결 성공\r\n");
            }
            catch { textBox1.AppendText("DB연결 실패\r\n"); }
            updateDataView();
        }
 
        public void updateDataView()
        {
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = con;
            cmd.CommandText = "select * from 성적표";
 
            mSqlDataAdapter = new SqlDataAdapter();
            mSqlDataAdapter.SelectCommand = cmd;
 
            mDataSet = new DataSet("성적관리");
            mSqlDataAdapter.Fill(mDataSet, "성적표");
 
            mDataTable = mDataSet.Tables["성적표"];
            dataGridView1.DataSource = mDataTable;
        }
    }
}




'Study > C#' 카테고리의 다른 글

IP 주소 정수로 변환  (0) 2017.05.16
C# Thread  (0) 2017.04.24
C# 네트워크 기본  (1) 2017.04.12
C# 예외처리, delegate  (0) 2017.04.10
C# 인터페이스  (0) 2017.04.07
728x90


C# 네트워크 프로그래밍


참고 도서 : 가볍게 시작하는 리얼 C# 프로그래밍


실 세계의 집주소는 네트워크에서는 IP 주소에 비유할 수 있다.

192.168.0.32


192는 가장 큰 범위 주소, 뒤로 갈수록 작은 범위의 주소이다.

ip주소와 Port 번호를 이용해 연결하며, Port 번호는 이름이라고 할 수도 있을 것이다.


TCP

TCP는 연결 지항형 서비스로, 데이터 전송 전에 Hand Shake를 통해 상대방과 연결을 형성한다.



UPD

UDP는 Hand Shake가 필요하지 않으며, 비연결형 서비스이므로 상대방과 1:1 회선이 형성되지 않는다. 

패킷에 상대방의 주소를 입력해 네트워크를 전송하며, 이는 편지에 비유할 수 있다. 통화는 바로 서로간 연결을 하지만, 편지는 써서 우체통에 넣을 뿐이니 말이다.



TCP의 혼잡 제어(Congestion Control)

특정 TCP 연결이 과도한 양의 데이터를 전송하려하면, 송신측의 TCP가 전송하려는 양의 데이터를 조절해서 (통신하는 호스트들 사이에)
네트워크 자원이 폭주되는 것을 방지한다.


TCP의 신뢰적 데이터 전달(Reliable data transfer)

TCP는 데이터가 순서대로, 정확하게 전달되는 것을 보장한다. TCP 연결이 이렇듯 많은 기능을 지원하지만, 

UPD에 비해선 연결이 무겁고 데이터 전송에 더 큰 비용이 든다. (흐름 제어, 순서번호, 확인 응답 등의 메커니즘을 사용하므로)


이런 이유로 UDP는 화면 공유 등에 주로 이용되고, TCP는 채팅 프로그램에 많이 사용된다.






내 PC의 IP 주소 출력하기

using System;
using System.Net;
 
 
namespace Network
{
    class Program
    {
        static void Main(string[] args)
        {
            string hostName = Dns.GetHostName();
            Console.WriteLine(hostName);
 
            IPHostEntry host = Dns.GetHostEntry(hostName);
            Console.WriteLine(host.AddressList[1].ToString());
 
            for (int i = 0; i < host.AddressList.Length; i++)
            {
                string myIPAddress = host.AddressList[i].ToString();
                Console.WriteLine(myIPAddress);
            }
        }
    }
}



네트워크 프로그래밍의 여러 클래스들


IPAddress 클래스


 도트 4자리 표기법의 IP 주소 예) 192.168.210.21


IPAddress 객체의 초기화 

IPAddress ipAddress = IPAddress.Parse("192.168.210.21");

IPAddress(Int64) // Int64로 지정된 주소 사용


.Parse // IP 주소 문자열을 IPAddress 인스턴스로 변환



IPEndPoint 클래스

하나의 컴퓨터에는 여러 프로그램이 동시 동작하므로, 원하는 프로그램을 찾기위해 포트 번호가 필요하다.

IPEndPoint는 특정 컴퓨터의 프로그램을 가리키는 클래스이다.


IPAddress ipAddress = IPAddress.Parse("192.168.210.21");
            IPEndPoint ipep = new IPEndPoint(ipAddress, 9999);

소켓 클래스

소켓 클래스는 실제 서버와 클라이언트를 구축하기 위해 필요한 인터페이스이다. 

소켓은 서로 다른 OS간에 네트워크 통신을 가능하게 해주며, 네트워크 전문 지식이 없이도 프로그래밍이 가능하게 한다.


이 과정을 크게 잡으면 다음과 같다.

1. 서버에서 소켓 생성 및 서버 설정 후 접속 대기

2. 접속이 일어나면 데이터 전송이 발생하고 소켓을 닫음



서버의 구현


이미지나 동영상 등의 전송을 위해선 byte로 데이터를 주고 받아야 한다.

using System; using System.Text; using System.Net; using System.Net.Sockets; namespace TCP_Server {     class Program     {         static void Main(string[] args)         {             Socket server = null;             Socket client = null;             byte[] data = new byte[1024];             // 3317포트에 대해선 모든 형태의 ip에 접속 허가             IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9999);             server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);             server.Bind(ipep);  // ipep를 통해 서버 소켓과 결합             server.Listen(10);  // 최대 접속 가능한 클라이언트의 수를 지정 후, 대기             Console.WriteLine("서버 시작 \n 클라이언트 접속 대기.");             // 클라이언트 접속 대기, 동기화 상태 진입. 접속이 일어나면 클라이언트 소켓이 반환             client = server.Accept();             Console.WriteLine("클라이언트 접속 완료.");             // 접속한 클라이언트로부터 데이터 수신, DATA 변수 BYTE 배열 형태로 저장             client.Receive(data);             Console.WriteLine("클라이언트로부터 데이터 수신. \n 메시지 : "                 + Encoding.Default.GetString(data));             // 클라이언트와 서버 소켓을 각각 닫는다.             client.Close();             server.Close();         }     } }



클라이언트의 구현

using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
 
namespace TCP_Client
{
    class Program
    {
        static void Main(string[] args)
        {
            byte[] data = new byte[1024];
 
            IPAddress ipAddress = IPAddress.Parse("210.119.12.79"); // 접속할 서버의 IP 주소            
            IPEndPoint ipep = new IPEndPoint(ipAddress, 9999); // 1433은 port번호, 특정 애플리케이션을 지정
 
            // 서버 소켓 생성
            Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
                ProtocolType.Tcp);
 
            Console.WriteLine("서버 접속...");
 
            // 서버 접속
            server.Connect(ipep);
            Console.WriteLine("서버 접속 완료.");
 
            data = Encoding.Default.GetBytes("클라이언트에서 보내는 메시지");
            server.Send(data);
            Console.WriteLine("서버에 데이터 전송");
 
            server.Close();
        }
    }
}


비동기화를 위한 thread 적용

동기화는 어떤 입력이 들어올 때까지 프로그램의 제어가 멈추어져 있으므로, 네트워크 접속에서는 비효율적이고 불편함을 초래한다.

반면에, 비동기화는 작업을 요청한 뒤 결과의 수신 여부와 상관없이 다음 작업을 곧바로 진행하므로 실시간 처리와 다중 접속 형태에 알맞다.


비동기화를 위해 thread를 이용할 수 있으며, 하나의 프로그램을 두 개 이상의 흐름으로 나누어 병렬로 실행할 수 있게 된다.

(하나의 thread는 Accept() 메소드를 실행하고, 기존의 프로그램 제어는 다른 thread가 담당)



커널 버퍼

https://colorscripter.com/s/dbnDSsE

위의 소스에서 Receive() 메소드는 상대에게서 바로 데이터를 받아오는 것이 아니다. 


Receive() 메소드를 호출하기 전에 이미 커널 버퍼에 데이터는 수신되어 있고, Receive() 메소드를 호출함으로써 가져오는 것이다.

이는 자원을 효율적으로 가져오기 위함이지만 문제가 있다. 


몇 번의 데이터를 수신하였는지 알 수 없고,  얼마 만큼 데이터를 한번에 처리해야 할지 알수 없는 것이다. 

이를 해결하기 위해서 패킷을 정의할 필요가 있다.



패킷의 정의

패킷은 네트워크 전송에 있어서 하나의 단위이다.


보통 TCP 통신을 통해 패킷을 전송할 때는 크게 두 가지 형태가 있다. 


여러 패킷을 모아 한번에 전송하거나, 하나의 패킷을 나누어서 여러 번에 걸쳐 전송하는 것이다. 

첫 번째는 데이터 크기가 작을 때 자원을 효율적으로 사용하기 위함이고, 두 번째는 데이터 크기가 클 때 내부 버퍼 용량과 전송 실패시의 부담을 고려한 것이다.



패킷의 정보 구성

데이터 패킷은 Header와 Body로 구성된다. 


헤더에는 한 패킷의 크기를 나타내는 정보가 담겨있다. 데이터 처리시 이 부분을 먼저 읽게 된다. 

바디에는 데이터가 들어있다.



필요에 따라 하나의 패킷이 다른 패킷에 포함될 수도 있다. 


패킷을 수신할 때, 패킷을 처리해 원하는 결과값을 얻을 것이다. 데이터의 종류는 수신 메시지 외에도 여러가지가 있다.

그렇기 때문에 패킷에는 데이터의 종류를 나타내는 정보도 담을 필요가 있다.


패킷 2는 데이터의 종류를 나타내는 헤더와 패킷 1로 구성될 수도 있다. 

(패킷 2 = 데이터의 종류를 나타내는 헤더 + 헤더와 데이터로 구성된 패킷 1)


패킷2의 헤더를 읽고 난 뒤에는 데이터의 종류를 알기에 패킷1의 데이터를 어디에서 처리할지 알 수 있다.

그 다음은 패킷1의 헤더를 통해 실제 데이터 크기를 알고 남은 데이터를 읽게 된다.



패킷1의 헤더에는 데이터의 총 크기가 담겨 있다. 

만약 수신한 데이터가 총 크기보다 작을 경우, 남은 데이터를 모두 읽을 때까지 반복하여 Receive() 함수를 호출하면 될 것이다.



패킷 개념을 적용한 소스는 다음과 같다. 우선 패킷으로 데이터를 수신하도록 Receive 함수의 일부분이 바뀌었다.

private void Receive()  // 상대 호스트로부터 데이터 수신 {     ( ... 생략)         //패킷 개념 적용을 위해 주석처리         //mClientSocket.Receive(data, SocketFlags.None);          data = ReceiveData();   // 정의한 패킷으로 데이터 수신                                                      message = Encoding.Default.GetString(data); // 수신데이터 string 형태로 데이터 변환         mChatWnd.ReceiveMessage(message);   // chat창에 메시지 전달                                     } }

다음과 같이 Send() 메소드의 일부분이 바뀌고 실질적인 데이터 전송은, 추가된 SendData 메소드를 통하도록 바뀌었다.

public void Send(string message)
{
    (... 생략)
 
    data = Encoding.Default.GetBytes(message);
    //mClientSocket.Send(data, 0, data.Length, SocketFlags.None);
    SendData(data);
}    


패킷 헤더의 크기를 상수로 정의하고 다음과 같이 패킷을 통한 전송/수신 메소드들을 추가하도록 한다.

private const int PACKET_HEADER_SIZE = 4;               // 패킷 해더 크기
 
        private byte[] ReceiveData()
        {
            byte[] headerBuffer = new byte[PACKET_HEADER_SIZE];
            byte[] dataBuffer = null;
 
            int totalDataSize = 0;  // 전체 데이터 크기
            int accumulatedDataSize = 0// 누적 수신한 데이터 크기
            int leftDataSize = 0;       // 미 수신 데이터 크기
            int receivedDataSize = 0;   // 총 수신한 데이터 크기
 
            // 데이터 수신. Receive 메소드 호출로 수신한 데이터 크기 저장
            receivedDataSize = mClientSocket.Receive(headerBuffer, 0, 
                PACKET_HEADER_SIZE, SocketFlags.None);
 
            // BitConverter 클래스의 메소드를 사용하기 위해 using System; 추가
            totalDataSize = BitConverter.ToInt32(headerBuffer, 0);
 
            leftDataSize = totalDataSize;
            dataBuffer = new byte[totalDataSize];
 
            while (leftDataSize > 0)
            {                
                receivedDataSize = mClientSocket.Receive(dataBuffer, accumulatedDataSize,
                    leftDataSize, 0); // 데이터 수신
 
                accumulatedDataSize += receivedDataSize; // 총 누적 수신 데이터
                leftDataSize -= receivedDataSize; // 남은 미 수신 데이터
            }
 
            return dataBuffer;  // 수신된 데이터 반환
        } 
 
        private void SendData(byte[] dataBuffer)
        {
            byte[] headerBuffer = new byte[PACKET_HEADER_SIZE];
 
            int totalDataSize = 0;  // 전체 데이터 크기
            int accumulatedDataSize = 0// 누적 전송한 데이터 크기
            int leftDataSize = 0;       // 미 전송 데이터 크기
            int sentDataSize = 0;   // 전송한 데이터 크기
 
            totalDataSize = dataBuffer.Length;
            leftDataSize = totalDataSize - sentDataSize;
                        
            headerBuffer = BitConverter.GetBytes(totalDataSize); // 전송할 데이터 총 크기
            mClientSocket.Send(headerBuffer);   // 전체 데이터 크기 전송
            
            while (leftDataSize > 0)
            {
                sentDataSize = mClientSocket.Send(dataBuffer, accumulatedDataSize,
                    leftDataSize, SocketFlags.None); // 데이터 전송
 
                accumulatedDataSize += sentDataSize; // 총 누적 전송 데이터
                leftDataSize -= sentDataSize; // 남은 미 전송 데이터
            }
        }

이렇게 패킷 개념을 적용해 프로그램을 작성하면 대용량의 데이터 전송/수신시에도 더 안정적으로 작동할 수 있게 된다.

좀 더 세심하게 예외처리까지 한다면 훨씬 안정적인 프로그램이 될 것이다.



c# winform 텍스트 박스 글씨 *로 보이기

TextBox 속성 중 PasswordChar에 *를 입력하면 된다. 이는 로그인 폼의 패스워드 입력을 위한 것이다.

'Study > C#' 카테고리의 다른 글

C# Thread  (0) 2017.04.24
C# MS-SQL 연동  (0) 2017.04.14
C# 예외처리, delegate  (0) 2017.04.10
C# 인터페이스  (0) 2017.04.07
C# 클래스, 메소드  (0) 2017.04.04
728x90

try~catch~finally

using System;
 
namespace Study
{
    class Program
    {
 
        static void Main(string[] args)
        {
            Console.WriteLine("입력 : ");
            string input = Console.ReadLine();
 
            try
            {
                int index = int.Parse(input);
                Console.WriteLine("입력 숫자 : " + index);
            }
            catch (Exception e)
            {
                Console.WriteLine("예외 발생 (int형이 아님)");
                Console.WriteLine(e.GetType());
                return;
            }
            finally
            {
                Console.WriteLine("프로그램 종료");
            }
        }
    }
}

catch에서 return하여 finally 절은 무조건 실행된다.(finally 가 없다면 "프로그램 종료" 문구가 나타나지 않고 종료될 것이다).

finally 절에서 return 키워드 같이 finally 절의 본문을 벗어나는 키워드는 사용할 수 없다.



throw 키워드


예외를 강제로 발생시킨다.

throw new Exception();



윈폼 예외처리


위와 같이 리스트 박스와 콤보박스를 이용해 윈폼을 디자인한다. 


그 다음 Product 클래스를 만들고 다음과 같이 작성한다.

class Product
{
    public string Name { getset; }
    public int Price { getset; }
}



콤보박스와 리스트 박스에 데이터 바인딩을 한다. 데이터 바인딩된 항목 사용에 체크하고 데이터 개체는 Product클래스를 선택한다.


각각 멤버와 값을 선택한다. 



이제 다음과 같이 데이터를 추가하면 데이터 박스와 리스트 박스에, 바인딩 된 데이터가 출력될 것이다.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
 
        productBindingSource.Add(new Product() { Name = "감자", Price = 500 });
        productBindingSource.Add(new Product() { Name = "사과", Price = 700 });
        productBindingSource.Add(new Product() { Name = "고구마", Price = 400 });
        productBindingSource.Add(new Product() { Name = "배추", Price = 600 });
        productBindingSource.Add(new Product() { Name = "감자", Price = 500 });
    }
}

데이터 그리드뷰도 마찬가지로 데이터 소스를 추가해 활용할 수 있다.




delegator (대리자)


델리게이트는 메소드의 매개변수로 메소드를 전달하기 위한 것이다. 델리게이터는 대리자라고 번역하기도 한다. 

말 그대로 어떤 행위를 대신 한다는 것으로, 행위(메소드)를 저장하고 전달하기 위해 나온 개념이다.


델리게이터 선언

delegate void TestDelegate();


델리게이터 자료형으로 변수 초기화

TestDelegate testDelegate = <메서드 이름, 무명 델리게이터, 람다> ( 이것은 델리게이터 변수를 초기화하는 방법이다)



Comparison 델리게이터 ( MSDN : https://msdn.microsoft.com/ko-kr/library/tfakywbh(v=vs.110).aspx )

public delegate int Comparison<in T>(
	T x,
	T y
)



다음은 Comparison 델리게이터를 이용해 상품의 가격을 정렬하는 예제이다. 

아래 예제에서는 Sort 메서드의 매개변수로 SortWithPrice 메소드를 전달한다.

namespace Delegate
{
    class Product
    {
        public string Name { getset; }
        public int Price { getset; }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            List<Product> products = new List<Product>()
            {
                new Product() {Name="감자", Price=500},
                new Product() {Name="사과", Price=700},
                new Product() {Name="상추", Price=300},                
            };
 
            products.Sort(SortWithPrice);
 
            foreach (var item in products)
            {
                Console.WriteLine(item.Name + " : " + item.Price);
            }          
        }
 
        static int SortWithPrice(Product a, Product b)
        {
            return a.Price.CompareTo(b.Price);
        }   
    }
}

Comparison은 델리게이트(대리자)로 형식에 맞는 함수를 따로 정의해 두어야 한다.

1
2
3
4
public static int Compare(float a, float b)
{
    return a.CompareTo(b); 
}
cs




'Study > C#' 카테고리의 다른 글

C# MS-SQL 연동  (0) 2017.04.14
C# 네트워크 기본  (1) 2017.04.12
C# 인터페이스  (0) 2017.04.07
C# 클래스, 메소드  (0) 2017.04.04
c# 복습  (0) 2017.03.31
728x90

인터페이스


1
2
3
4
interface ILogger // 첫글자 대문자로 적는건 약속
{
    
}
cs

인터페이스는 public

객체생성이 이뤄지지않는 껍데기


상속받은 자식클래스에서는 부모클래스에서 명시한 기능을 구현해야함

실제구현은 자식클래스

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace Interface
{
    interface ICar
    {
        void drive(string msg);
    }
 
    interface IAirplane
    {
        void fly(string msg);
    }
 
    class Machine : ICar
    {
        public void drive(string msg)
        {
            Console.WriteLine(msg);
        }
    }
    class Machine2 : IAirplane
    {
        public void fly(string msg)
        {
            Console.WriteLine(msg);
        }
    }
    class MainApp
    {
        static void Main(string[] args)
        {
            Machine m1 = new Machine();
            Machine2 m2 = new Machine2();
        }
    }
}



죽음의 다이아몬드 

: c#에서 클래스 다중상속을 허용하지 않는 이유는 죽음의 다이아몬드 때문이다.

프로그램에서 같은 구문이 두 가지 이상의 의미로 해석될 여지가 있어서는 안 된다





하지만, 인터페이스를 사용하면 다중상속이 가능하다.


인터페이스를 사용하는 이유는 다음과 같다.

  • 자식단에서 구현할 메소드를 미리 구현
  • 메소드의 이름만 물려받고 자식클래스에서 재정의


IComparable 인터페이스

인터페이스는 모두 대문자 I 로 시작한다. IComparable 인터페이스는 비교할 때 사용되는 규약이다.

using System; using System.Collections; using System.Collections.Generic; namespace Study {     class Program     {         class Product         {             public string Name { getset; }             public int Price { getset; }             public override string ToString()             {                 return Name + " : " + Price + "원";             }         }               static void Main(string[] args)         {             List<Product> list = new List<Product>()             {                 new Product() {Name= "고구마", Price=1500},                 new Product() {Name= "사과", Price=2400},             };             list.Sort();             foreach(var item in list)             {                 Console.WriteLine(item);             }         }     } }


위의 프로그램은 Sort() 메서드가 정렬의 기준을 알지 못하기 때문에 오류가 발생한다. 이러한 기준을 정해주기 위해 IComparable 인터페이스를 구현한다.

해당 클래스에서 IComparable 인터페이스를 상속받아 사용한다.


IComparable에 커서를 놓고 Ctrl + .  단축키를 누르면 다음과 같이 인터페이스를 쉽게 구현할 수 있다. 



인터페이스 구현을 누르면 다음과 같이 CompareTo 메서드도 자동 생성된다.

public int CompareTo(object obj)
           {
               throw new NotImplementedException();
           }

CompareTo 메서드를 다음과 같이 변경해보자. obj가 Product이면 가격을 비교해 반환하겠다는 뜻이다. 오름차순으로 정렬된다.

public int CompareTo(object obj)
          {
              return this.Price.CompareTo((obj as Product).Price);
          }


내림차 순으로 정렬하고 싶다면 다음과 같이 변경하면 될 것이다.

public int CompareTo(object obj)
{
    return (obj as Product).Price.CompareTo(this.Price);
}


using 키워드와 IDisposable 인터페이스


아래 예제에서는 IDisposable 인터페이스를 상속받은 클래스 Dummy의 인스턴스를 using 블록의 괄호 내에서 생성한다.

Dispose() 메서드를 따로 호출하지 않아도 using 블록을 벗어날 때 호출된다.

using System;

namespace Study
{
    class Program
    {
        class Dummy : IDisposable
        {
            public void Dispose()
            {
                Console.WriteLine("Dispose() 메서드 호출");
            }
        }


        static void Main(string[] args)
        {
            using (Dummy dummy = new Dummy())
            {
 
            }
        }
    }
}



파일 입출력

using System.IO;

파일을 쓸 때 사용하는 StreamWriter는 IDisposable 인터페이스를 구현한 대표적인 클래스이다.


아래 파일 입출력 경로를 보면 @ 기호가 쓰인 것을 볼 수 있다.

문자열 내부에서 \ 기호는 특수한 의미를 지니기 때문에 원래는 \\를 사용해야 한다.


하지만 @ 기호를 붙여 문자열을 만들면 \\기호를 여러번 쓰지않아도 된다. 다만 내부에서 이스케이프 문자를 사용할 수 없게 된다.


using System;
using System.IO;
 
namespace Study
{
    class Program
    {
        static void Main(string[] args)
        {
            string path = @"c:\tesst\test.txt";
            string textValue = "시간 - " + DateTime.Now;
 
            try
            {
                File.WriteAllText(path, textValue);
                Console.WriteLine("읽은 문자열 : " + File.ReadAllText(path));        
            }
            catch (Exception)
            {
 
                Console.WriteLine("파일을 읽거나 쓸 수 없습니다");
            }
        }
    }
}


스트림으로 쓰기


큰 용량의 파일을 한꺼번에 읽고 쓰는 것은 시스템에 부담이 가기 때문에 파일을 한 줄씩 읽고 쓸 수 있는 다양한 방법이 있다.

StreamWrite 클래스를 이용하면 스트림으로 쓸 수 있다.


StreamWrite 클래스는 TextWriter의 상속을 받는다.

// 요약:
//     System.IO.TextWriter를 구현하여 특정 인코딩의 스트림에 문자를 씁니다.
[Serializable]
[ComVisible(true)]
public class StreamWriter : TextWriter


TextWriter는 abstract class로 MarshalByRefObject, IDisposable의 상속을 받는다.

이를 통해 IDisposable 인터페이스를 구현한 클래스라는 것을 알 수 있다.

public abstract class TextWriter : MarshalByRefObjectIDisposable


다음은 StreamWrite 클래스로 파일에 여러 문자열을 쓰는 예제이다.

static void Main(string[] args)
        {
            string path = @"c:\test\test.txt";
 
            using (StreamWriter writer = new StreamWriter(path))
            {
                writer.WriteLine("안녕");
                writer.WriteLine("여러줄을");
                writer.WriteLine("입력해봄");
            }
 
            Console.WriteLine(File.ReadAllText(path));
        }



StreamReader 클래스로 한줄씩 읽기


아래는 잘못된 예제이다. 한 줄을 읽고 따로 값이 저장되지 않았기에 2번째 줄만 출력된다.

class Program
    {
        static void Main(string[] args)
        {
            string path = @"c:\test\test.txt";
 
            using (StreamReader reader = new StreamReader(path))
            {
                while (reader.ReadLine() != null)
                {                    
                    Console.WriteLine(reader.ReadLine());
                }
            }
        }
    }

바른 예

static void Main(string[] args)
        {
            string path = @"c:\test\test.txt";
 
            using (StreamReader sr = new StreamReader(path))
            {
                while (sr.Peek() >= 0)
                {
                    Console.WriteLine(sr.ReadLine());
                }
            }
        }


using을 사용하지 않은 예

class Program
{
    static void Main(string[] args)
    {
        string path = @"c:\test\test.txt";
 
        StreamReader reader = new StreamReader(path);
        string line;
 
        while ((line = reader.ReadLine()) != null)
                Console.WriteLine(line); 
    }
}


인터페이스, 내용 정리


인터페이스는 다중 상속이 가능하다.

public class MyConnection : Component, IDbConnection, IDisposable
{
}


인스턴스 변수를 가질 수 없다.

오류 : 인터페이스 멤버에는 정의를 사용할 수 없습니다.

interface IBasic
        {
            void TestMethod()
            {
 
            }
        }

인터페이스는 인스턴스 메서드를 가질 수 있다.


인터페이스는 클래스 변수를 가질 수 없다.

인터페이스는 클래스 메서드를 가질 수 없다.


인터페이스는 속성(Property)을 가질 수 있다.

'Study > C#' 카테고리의 다른 글

C# 네트워크 기본  (1) 2017.04.12
C# 예외처리, delegate  (0) 2017.04.10
C# 클래스, 메소드  (0) 2017.04.04
c# 복습  (0) 2017.03.31
headfirst c#-wpf  (0) 2016.11.19
728x90

윈폼에서 코드로 디자인

namespace CS_Windows_Forms
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
 
            myButton.Text = "코드에서 변경!";
            myButton.Width = 200;
 
            for (int i = 0; i < 5; i++)
            {
                Button btn = new Button();
                Controls.Add(btn);
                btn.Location = new Point(2080 + i * 30);
                btn.Text = i + " 동적 생성";
            }
        }
    }
}

결과 화면



폼 디자인 코드에서 생성자 정의하기

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
 
            Button btn = new Button();
            Controls.Add(btn);
            btn.Location = new Point(2080);
            Box box = new Box(btn);
            
        }
    }
    class Box
    {
        public Box(Button btn)
        {
            btn.Text = "버튼 전달";
        }
    }






생성자 정의하고 버튼으로 값 변경하기

namespace CS_Windows_Forms
{
    public partial class Form1 : Form
    {
        Box box;
 
        public Form1()
        {
            InitializeComponent();
 
            Button btn = new Button();
            Controls.Add(btn);
            box = new Box(btn);
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            box.Area();
        }
    }
    class Box
    {
        Button btn;
 
        public Box(Button btn)
        {
            this.btn = btn;
            btn.Text = "버튼 전달";
        }
 
        public void Area()
        {
            if (btn.Width > 250)
                MessageBox.Show("더 이상 늘릴 수 없습니다");
 
            else
            {
                btn.Width += 10;
                btn.Height += 10;
            }
        }
    }
}




static 키워드

static이라는 키워드를 붙인 변수 또는 메서드는 프로그램을 실행하는 순간에 메모리가 올라가게 된다.

이때는 객체의 생성없이 메서드


Code Snippet
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.Collections;
  7. using System.Threading;
  8.  
  9. namespace SScore
  10. {
  11.     class Test
  12.     {
  13.         public static int Abs(int n)
  14.         {
  15.             if (n < 0)
  16.                 return -n;
  17.  
  18.             else
  19.                 return n;
  20.         }
  21.     }
  22.  
  23.     class Program
  24.     {
  25.         static void Main(string[] args)
  26.         {
  27.             //Test test = new Test();
  28.             int num = Test.Abs(-10);
  29.             Console.WriteLine(num);
  30.         }
  31.     }
  32. }




C#의 구조체


c#에서도 구조체를 쓸 수 있다. c#에서는 구조체 멤버 변수도 기본적으로 private로 보호된다.


namespace SScore
{
    public struct MyPoint
    {
        public int x;
        int y;
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            MyPoint point;
            Console.WriteLine(point.x);
            Console.WriteLine(point.y); // 오류 : 보호 수준 때문에 'SScore.MyPoint.y'에 액세스할 수 없습니다.	
 
        }
    }
}


private 생성자

기본적으로 생성자는 public 접근 제한자를 쓰지만, 

생성자로 클래스의 인스턴스를 만들 수 없게 할 때는 private 생성자를 사용한다.

namespace SScore
{
    class Hidden
    {
        private Hidden();
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            Hidden hidden = new Hidden();   // 오류
        }
    }
}

위와 같이 메인 메소드에서 인스턴스를 생성하려고 하면 다음과 같은 오류를 출력한다.

오류	: 'SScore.Hidden.Hidden()'은(는) abstract, extern 또는 partial로 
            표시되어 있지 않으므로 본문을 선언해야 합니다.

private 생성자를 이용하는 이유는 다음과 같다.


  • 정적 멤버(static member)만 가지고 있을때
  • 팩토리 메서드 패턴에서 팩토리 메서드로만 인스턴트를 생성하게 하고 싶을 때 (디자인 패턴중의 하나로, 부모 클래스에서 숨겨진 자식 클래스의 인스턴스를 만드는 형태)



정적 생성자 (static constructor)

정적 생성자는 정적(static)요소를 초기화 할때에 사용된다.

정적 생성자를 만들 때는 접근 제한자와 매개변수를 사용하지 못한다.

class Sample
{
    public static int value;
 
    static Sample()
    {
        value = 10;
        Console.WriteLine("정적 생성자 호출");            
    }
}
 
class Program
{
    static void Main(string[] args)
    {
        Sample sample = new Sample();   // 이 때 한번만 호출
        Console.WriteLine();
        Console.WriteLine(Sample.value);
    }
}

출력 : 

정적 생성자 호출


10



readonly 키워드 (read only)

읽기 전용 키워드인 readonly로 변수를 선언하면 값을 변경할 수 없게 된다. 

class Sample
   {        
       public readonly int id=0;
 
       public Sample()
       {
           this.id++;
           Console.WriteLine("생성자 호출");            
       }
   }
 
   class Program
   {
       static void Main(string[] args)
       {
           Sample sample = new Sample();   
           Console.WriteLine(sample.id);
       }
   }

읽기 전용 필드의 값을 변경하려 할 때 다음과 같은 오류 메시지를 출력한다. 다만, 생성자에서는 readonly 키워드 변수도 값을 변경할 수 있다.



Getter와 Setter

값을 은닉화하면서 의도치 않은 값으로 초기화하는 걸 방지할 때에는 게터와 세터를 사용한다.

get 접근자는 값을 반환하고, set 접근자는 값을 할당한다.

class Unsigned
{
    private int num;
    public int Num
    {
        get { return num; }
        set
        {
            if (value > 0) { num = value; }
            else { Console.WriteLine("num변수는 양수여야 합니다."); }
        }
    }
}
 
class Program
{
    static void Main(string[] args)
    {
        Unsigned unsigned = new Unsigned();
        unsigned.Num = -10;            
    }
}

Output : 

num변수는 양수여야 합니다.




게터와 세터를 더 쉽게 쓰려면 prop라고 입력하고  tap키를 두번 누르면 코드 조각이 자동으로 생성된다.

public int MyProperty { getset; }


propfull을 입력한 상태에서 tap키를 두 번 누르면 다음 형태의 코드 조각이 자동으로 생성된다.

private int myVar;
 
        public int MyProperty
        {
            get { return myVar; }
            set { myVar = value; }
        }




상속

using System;
using System.Collections;
using System.Collections.Generic;
 
namespace Study
{
    class Animal
    {
        public string name;
        public void Eat()
        {
            Console.WriteLine("냠냠");
        }
        public void Sleep()
        {
            Console.WriteLine("쿨쿨");
        }
    }
 
    class Dog : Animal
    {
        public void Bark()
        {
            Console.WriteLine("왈왈");
        }
    }
    class Cat : Animal
    {
        public void Meow()
        {
            Console.WriteLine("냐옹");
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
 
            List<Animal> Animals = new List<Animal>()
            {
                new Dog(){name="멍멍이"}, new Cat(){name="냐옹이"}
            };
 
            foreach(var item in Animals)
            {
                Console.WriteLine(item.name);
                item.Eat();
                item.Sleep();
 
                ((Dog)item).Bark();
            }
        }
    }
}

위의 프로그램을 실행시키면 다음과 같은 예외가 발생한다.


출력결과 :

멍멍이

냠냠

쿨쿨

왈왈

냐옹이

냠냠

쿨쿨


처리되지 않은 예외: System.InvalidCastException: 'Study.Cat' 형식 개체를 'Study.

Dog' 형식으로 캐스팅할 수 없습니다.


((Dog)item).Bark();

List에 Dog와 Cat 클래스의 인스턴스가 같이 존재하기 때문에 Cat 형식 개체를 Dog 형식 개체로 형변환 할 때 오류가 발생하는 것이다.

이를 해결하기 위해서는 조건문을 통해 item이 Dog객체인지 Cat 객체인지를 판별하게 해야 한다. 


is 키워드를 사용하면 특정 클래스의 객체일 때 true를 반환하게 된다.

다음과 같이 foreach 구문의 내용을 변경하고 실행해보자.


foreach(var item in Animals)
            {
                Console.WriteLine(item.name);
                item.Eat();
                item.Sleep();
 
                if (item is Dog)
                    ((Dog)item).Bark();
 
                else
                    ((Cat)item).Meow();
            }

실행 결과 :

멍멍이

냠냠

쿨쿨

왈왈

냐옹이

냠냠

쿨쿨

냐옹



섀도잉 (Shadowing)


변수의 이름이 겹칠 때 자신과 가장 가까운 변수를 사용한다. 아래 프로그램에서는 메인 메소드 내부가 된다.

class Program
   {
       public static int num = 20;
 
       static void Main(string[] args)
       {
           int num = 40;
           Console.WriteLine(num);
       }
   }

출력 결과 :

40



하이딩(Hiding)과 오버라이딩(Overriding)


부모 클래스와 자식 클래스 사이에는 이를 Hiding 이라고 한다. 상속하는 멤버가 아닌 자신의 클래스 내부의 변수를 사용한다.

숨겨진 변수나 메소드를 쓸 때는, 부모로 형변환을 통해 쓸 수 있다.


Code Snippet
  1. using System;
  2. namespace Study
  3. {
  4.     class Parent
  5.     {
  6.         public int q = 10;
  7.     }
  8.  
  9.     class Child : Parent
  10.     {
  11.         public new string q = "20";
  12.     }
  13.  
  14.     class Program
  15.     {
  16.         static void Main(string[] args)
  17.         {
  18.             Child child = new Child();
  19.             Console.WriteLine(child.q);
  20.             Console.WriteLine("" + ((Parent)child).q);
  21.         }
  22.     }
  23. }


출력결과 

20

10


static void Main(string[] args)
        {
            Child child = new Child();
            Parent parent = child;

            Console.WriteLine(child.q);
            Console.WriteLine(parent.q);
        }


메소드 하이딩

숨기려면 new 키워드를 사용해 하이딩 함을 명확하게 알려주는 것이 좋다. (에러는 띄우지 않지만 경고를 띄움)

메서드는 변수와 달리, 이름이 겹칠 때 하이딩할지 오버라이딩 할지 결정할 수 있기 때문이다.

using System;
namespace Study
{
    class Parent
    {
        public int variable = 273;
 
        public void Method()
        {
            Console.WriteLine("부모 메서드");
        }
    }
 
    class Child : Parent
    {
        public new void Method()
        {
            Console.WriteLine("자식 메서드");
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            Child child = new Child();
            child.Method();
            ((Parent)child).Method();
        }
    }
}


메소드 오버라이딩

부모의 메서드를 virtual 키워드로 정의하면, 자식 클래스에서 override 될 수 있다.

이 때 자식의 메소드가 부모 메서드를 덮어 씌우고 새로 정의된다.

using System;
namespace Study
{
    class Parent
    {
        public virtual void Method()
        {
            Console.WriteLine("부모 메서드");
        }
    }
 
    class Child : Parent
    {
        public override void Method()
        {
            Console.WriteLine("자식 메서드");
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            Child child = new Child();
            child.Method();
            ((Parent)child).Method();
        }
    }
}

Output :

자식 메서드

자식 메서드




sealed 키워드


클래스에 적용하면 : 절대 상속하지 못하게 함

메서드에 적용하면 : 더 이상 오버라이드하지 못하게 함



abstract(추상) 키워드


클래스에 적용하면 : 무조건 상속해서 쓰게 함. 해당 클래스 자체에서 인스턴스를 만들수 없게 됨


메서드에 적용하면 

: 반드시 오버라이드해서 쓰게 함, 이 때 메서드는 본문을 선언할 수 없으므로, 중괄호 {}를 쓰지 않고 곧바로 세미콜론 ; 으로 문장을 마침.

  abstract 메서드 선언을 위해 클래스도 abstract 클래스가 되어야 함. 따로 virtual 키워드를 쓰지 않아도 됨




Generic

using System;
namespace Study
{
    class Wanted <T>
    {
        public T value;
        public Wanted(T value)
        {
            this.value = value;
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            Wanted<string> wantedString = new Wanted<string>("String");
            Wanted<int> wantedint = new Wanted<int>(12);
 
            Console.WriteLine(wantedString.value);
            Console.WriteLine(wantedint.value);
        }
    }
}

T는 형식매개변수(Type Parametor)를 뜻하며, 하나의 약속이다. 이와 같이 변수 value 자료형을 원하는 자료형으로 지정 가능하다.




Out 키워드

using System;

namespace Study
{
    class Program
    {
        static void Main(string[] args)
        {
            string s="0404";
            int output;

            bool result = int.TryParse(s, out output);

            if (result)
            {
                Console.WriteLine(output);
            }
            else
                Console.WriteLine("숫자로 변환불가");
        }
    }
}


'Study > C#' 카테고리의 다른 글

C# 예외처리, delegate  (0) 2017.04.10
C# 인터페이스  (0) 2017.04.07
c# 복습  (0) 2017.03.31
headfirst c#-wpf  (0) 2016.11.19
5/27 업무일지 c#학생성적관리(콘솔)  (0) 2016.05.27
728x90

Object 형식

어떤 형식의 데이터라도 object에 담아 처리할 수 있다. (int, long, char, bool, string...)


ex) object a=123;    object b=3.14f;    object c = true;    object d = "hello";




나머지 연산자 %

실수에 나머지 연산자 % 를 쓰는 건 추천하지 않는다.

static void Main(string[] args)
        {
            Console.WriteLine(5.0 % 2.2);
        }

정수라면 실행 결과로 2를 출력하겠지만 여기서는 0.6을 출력한다.

5.0 - (2.2 * 2) = 0.6 



문자열

문자열은 다음과 같이 더할 수 있다.

하지만 문자 (한 글자)는 더할 수 없고, 문자를 숫자로 생각해 더하게 된다.


문자를 연결하고 싶다면 ' '로 감싸지말고 문자열을 뜻하는 " " 로 감싸야한다. 

static void Main(string[] args)
      {
          Console.WriteLine("가나다" + "라마" + '바');
          Console.WriteLine("안녕하세요" [0]);
          Console.WriteLine("안녕하세요" [2]);
      }

출력 결과 :

가나다라마바



숫자와 문자열을 더하면 자동으로 문자열로 형변환된다.

하지만 숫자와 '문자'를 더하면 아스키 코드값으로 출력된다.

static void Main(string[] args)
       {
           Console.WriteLine(2 + '3' + "4");
           Console.WriteLine(2 + '3' + '4');
       }

출력결과 :

534

105




다른 자료형을 bool로 변환

다음과 같은 경우 23번째 줄에서 에러를 출력한다.
Code Snippet
  1. static void Main(string[] args)
  2.         {
  3.             Console.WriteLine(bool.Parse("True"));
  4.             Console.WriteLine(bool.Parse("true"));
  5.             Console.WriteLine(bool.Parse("test"));
  6.         }


bool은 true, false 데이터를 다루며 1바이트 크기의 type이다. (1비트만으로 표현가능하지만 컴퓨터가 기본적으로 바이트 단위를 사용하므로)



오버플로우 확인하기

static void Main(string[] args)
        {
            int num = int.MaxValue;
            Console.WriteLine(num+1);
        }   

오버플로우를 일으키며 -2147483648 이라는 값을 출력한다.

다음과 같이 double로 형변환하면 해결 가능하다.

static void Main(string[] args)
       {
           int num = int.MaxValue;
           Console.WriteLine((double)num+1);
       }   

혹은 num을 선언할 때 unsigned 자료형으로 선언해 해결할 수도 있다.

uint num = int.MaxValue;




음수의 음수?


Code Snippet
  1. static void Main(string[] args)
  2.         {
  3.             Console.WriteLine(-(-1));
  4.             
  5.             int output = int.MinValue;
  6.             Console.WriteLine(-(output));
  7.             Console.WriteLine(-(-2147483648));
  8.         }


위 소스 25번째 줄에서 다음과 같은 오류를 일으킨다.


checked 모드에서 컴파일하면 작업이 오버플로됩니다.

25번째 줄을 주석처리하면 다음과 같은 결과가 출력된다.

출력결과 :
1
-2147483648


키 입력을 출력
static void Main(string[] args)
        {
            Console.ReadKey();
        }
위의 예제를 실행하면 사용자가 누른 키를 콘솔 화면에 표시한다.


ReadKey() 메서드는 ConsoleKeyInfo 객체를 받게 되고, 이 객체 내부의 KeyChar 속성을 통해 입력 키를 알아낸다.
public static ConsoleKeyInfo ReadKey();
public static ConsoleKeyInfo ReadKey(bool intercept);





지정된 크기의 배열 생성


값을 넣지않고 초기화하면 기본 값으로 공간이 채워진다. (숫자 자료형은 0, 문자열 자료형은 빈 문자열, 객체는 null로 초기화)

static void Main(string[] args)
       {
           int[] intArray = new int[100];
 
           Console.WriteLine(intArray[0+ "\n" + intArray[99]);
       }


배열 요소를 마지막 요소에서부터 출력

static void Main(string[] args)
        {
            int[] intArray = { 123456 };
 
            for (int i = intArray.Length - 1; i >= 0; i--)
                Console.Write(intArray[i] + " ");
        }

출력결과 : 6 5 4 3 2 1



List 클래스를 이용한 가변적인 크기의 배열 생성

List<> 에서 <>안에는 Generic으로 어떤 자료형인지를 미리 알려준다.

static void Main(string[] args)
       {
           Random random = new Random();
 
 
           List<int> list = new List<int>();
 
           for (int i = 0; i < 6; i++ )
               list.Add(random.Next(1100));
 
           for (int i = 0; i < list.Count; i++)
               Console.Write(list.ElementAt(i) + " ");
       }   


List활용예제

이름, 학점, 영어 입력받고 학점 4.0 이상이고 영어점수가 900점 이상인 리스트를 출력


C#에서 클래스는 앞글자 대문자, 변수명은 소문자를 쓴다. (절대 규칙은 아니지만 권장)


이외의 네이밍 규칙 http://zepeh.tistory.com/115


Code Snippet
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.Collections;
  7.  
  8.  
  9. namespace SScore
  10. {
  11.     class Student
  12.     {
  13.         public string name;
  14.         public double grade;
  15.         public int eng;
  16.     }
  17.     class Program
  18.     {
  19.         static void Main(string[] args)
  20.         {
  21.             List<Student> list = new List<Student>();
  22.  
  23.             for (int i = 0; i < 3; i++)
  24.             {
  25.                 Student s = new Student();
  26.  
  27.                 Console.Write("이름:");
  28.                 s.name = Console.ReadLine();
  29.                 Console.Write("학점:");
  30.                 s.grade = double.Parse(Console.ReadLine());
  31.                 Console.Write("영어:");
  32.                 s.eng = int.Parse(Console.ReadLine());
  33.  
  34.                 list.Add(s);
  35.             }
  36.             for (int i = 0; i < list.Count; i++)
  37.             {
  38.                 if (list.ElementAt(i).grade < 4.0 || list.ElementAt(i).eng < 900)
  39.                     break;
  40.                    
  41.  
  42.                 Console.WriteLine(list.ElementAt(i).name + "," +
  43.                     list.ElementAt(i).grade + "," +
  44.                     list.ElementAt(i).eng);                
  45.             }
  46.         }
  47.     }
  48. }



Generic

제네릭은 클래스 자료형을 지정하는 기능이다.  형식 매개 변수 T를 사용 하고 선언할 때 Name<T>의 형태를 가진다. 
두 개 이상을 지정하려면 T, U와 같이 쓴다.

namespace Generic
{
    class Wanted<T, U>
    {
        public T value;
        public U value2;
 
        public Wanted(T value, U value2) 
        {
            this.value=value;
            this.value2 = value2;
        }
    }    
    class Program
    {
        static void Main(string[] args)
        {
            Wanted<stringint> StringAndInt = new Wanted<stringint>("String"32);
 
            Console.WriteLine(StringAndInt.value + "\n" + StringAndInt.value2);
        }
    }
제네릭의 가장 일반적인 사용은 컬레션 클래스를 만드는 것이지만, 클래스나 인터페이스, 메서드, 대리자에도 사용된다.


Indexer
인덱서를 이용하면 클래스나 구조체의 인스턴스를 배열처럼 인덱싱할 수 있다.
인덱서는 프로퍼티와 유사하지만 반드시 인스턴스 멤버로만 존재하여야 한다. (static 선언 불가)
class Sign
{
    public int this[int i]
    {
        get { return (-i); }
    }
}
 
class Program
{
    static void Main(string[] args)
    {
        Sign sign = new Sign();
        Console.WriteLine(sign[15]);
    }
}

'Study > C#' 카테고리의 다른 글

C# 인터페이스  (0) 2017.04.07
C# 클래스, 메소드  (0) 2017.04.04
headfirst c#-wpf  (0) 2016.11.19
5/27 업무일지 c#학생성적관리(콘솔)  (0) 2016.05.27
c# 클래스 복습2  (0) 2016.05.23

+ Recent posts