일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- string
- Python
- Redshift
- dataframe
- hive
- PostgreSQL
- Google Excel
- Github
- GIT
- 파이썬
- Google Spreadsheet
- Kotlin
- PANDAS
- Mac
- array
- gas
- Apache
- SQL
- Java
- matplotlib
- math
- Tkinter
- PySpark
- Excel
- google apps script
- c#
- numpy
- django
- list
- Today
- Total
달나라 노트
C# : EventHandler (마우스 이벤트 처리) (Window 클릭, 버튼 클릭, 마우스 오버, Window click, Button click, mouse over) 본문
C# : EventHandler (마우스 이벤트 처리) (Window 클릭, 버튼 클릭, 마우스 오버, Window click, Button click, mouse over)
CosmosProject 2022. 3. 30. 19:12
마우스 클릭, 마우스의 위치 변화, 키보드 입력 등 사용자로부터 발생한 어떠한 변화를 이벤트(Event)라고 합니다.
C#에서는 "Event가 발생하면 무엇을 해라" 라는 기능을 구현할 수 있습니다.
아래 코드를 봅시다.
using System;
using System.Windows.Forms;
class MyProgram
{
public static void Main()
{
Form fm = new Form();
fm.Text = "Sample Window";
fm.Width = 300;
fm.Height = 200;
Label lbl = new Label();
lbl.Text = "Welcome!";
lbl.Parent = fm;
Application.Run(fm);
}
}
코드를 실행하면 위 이미지같은 창이 뜹니다.
Window의 Form 라이브러리를 이용해서 윈도우 창을 띄운겁니다.
이제 위 코드를 부분별로 해석해봅시다.
Form fm = new Form();
fm.Text = "Sample Window";
fm.Width = 300;
fm.Height = 200;
먼저 Form 객체 생성 부분입니다.
일단 Form이란 위 이미지처럼 윈도우 창을 의미합니다.
Form() class는 System.Windows.Forms 하위에 있는 class입니다. 이미 C#에서 제공하는 기능이죠.
원래 System.Windows.Forms.Form 이렇게 사용해야하지만 using 구문으로 우리는 이미 Forms까지를 import해놨기 때문에 단순히 Form 이라는 글자만 이용하여 Form의 기능을 사용할 수 있습니다.
Form class로 만들어진 fm 객체에는 여러 속성이 있습니다.
fm.Text -> 윈도우의 제목을 설정하는 부분입니다. 위 이미지를 보면 가장 상단에 Window 제목이 Sample Window로 설정된걸 볼 수 있죠.
fm.Width -> 윈도우의 가로 길이를 의미합니다.
fm.Height -> 윈도우의 세로 길이를 의미합니다.
Label lbl = new Label();
lbl.Text = "Welcome!";
lbl.Parent = fm;
이번에는 Label class를 이용해서 lbl 객체를 생성하고 있습니다.
Label은 간단하게 말하면 텍스트 박스입니다.
제가 원하는 텍스트를 담을 수 있는 텍스트 박스이죠.
lbl.Text -> 텍스트 박스에 표시할 문자입니다.
lbl.Parent -> lbl 객체로 만들어진 텍스트 박스가 어디에 속해서 표시될지를 정하는 부분입니다. 단순히 Label 만 설정해두면 C#은 이 라벨을 어디다가 표시해야할지 모릅니다. 그래서 lbl.Parent = fm; 이라고 명시해줘서 "이 Label의 부모객체는 fm 객체니까 fm 객체로 생성되는 Window 내부에 라벨을 띄워줘."라는 의미인 것입니다.
Application.Run(fm);
이것은 생성한 Form을 실행하여 실제 아래와 같은 창을 띄워주는 구문입니다.
Run method의 인자로서 fm(Form 객체)를 받았으니 제가 생성하고 제가 구성한 fm 객체의 정보를 기반으로 Window가 나타나게됩니다.
자 여기까지 하면 굉장히 간단한 단순히 문자를 표시해주는 Window를 띄우는 것 까지는 가능하게 되었습니다.
그러면 이제 Window를 띄우고 창을 클릭하면 표시되는 텍스트를 변경하는 코드를 작성해봅시다.
이전에 봤던 예시와 동일하지만 몇줄이 추가되었습니다.
아래 코드를 보시죠.
using System;
using System.Windows.Forms;
class MyProgram
{
public static void Main()
{
Form fm = new Form();
fm.Text = "Sample Window";
fm.Width = 300;
fm.Height = 200;
Label lbl = new Label();
lbl.Text = "Welcome!";
lbl.Parent = fm;
void fm_event_click(Object sender, EventArgs e) // 추가됨
{
lbl.Text = "You clicked.";
}
fm.Click += new EventHandler(fm_event_click); // 추가됨
Application.Run(fm);
}
}
위 코드를 실행해봅시다.
그러면 위같은 창이 뜹니다.
그리고 나타난 Window를 마우스로 클릭하면 표시되는 문자가 You clicked. 로 바뀝니다.
이렇게 User의 행동(input)에 따라 어떠한 작동을 하도록 하는게 EventHandler입니다.
위 코드에서 추가된 부분(EventHandler 관련 부분)을 보시죠.
void fm_event_click(Object sender, EventArgs e)
{
lbl.Text = "You clicked.";
}
fm.Click += new EventHandler(fm_event_click);
바로 이 부분이 EventHandler와 관련된 부분입니다.
Event를 처리하기 위해서는 크게 2가지가 필요합니다.
1. Event가 발생했을 때 어떤 동작을 할지를 정해둔 method 생성
2. 생성한 method를 EventHandler에 등록
1번은 fm_event_click 이라는 method를 생성함으로써 완료했고,
2번은 fm_event_click method를 EventHandler에 등록함으로써 완료했습니다.
먼저 Event 발생 시 어떤 동작을 할지에 대한 내용을 담은 method 선언 부분을 봅시다.
void fm_event_click(Object sender, EventArgs e)
{
lbl.Text = "You clicked.";
}
method의 선언은 일반적인 method 선언과 다르지 않습니다.
method의 이름도 원하는대로 정하면 됩니다.
다만 EventHandler에 등록할 Event method는 인자로서 Object sender와 EventArgs e를 받아야합니다.
Object sender 는 어떤 객체 타입의 sender라는 변수입니다.
EventArgs e는 EvetnArgs 타입의 e라는 변수입니다.
Object sender는 Event가 발생한 객체를 의미합니다.
Object sender 관련 내용은 아래에서 좀 더 자세히 다루겠습니다.
그리고 method의 내용은 Event가 발생했을 때 실행할 동작을 담고 있습니다.
여기서는 라벨의 텍스트(lbl.Text)를 You clicked.로 설정하는 내용이 담겨있죠.
fm.Click += new EventHandler(fm_event_click);
이제 생성한 Event method를 EventHandler에 등록하는 과정입니다.
코드를 실행해서 나타난 윈도우를 클릭하면 글자가 변하게 할 것이니까 당연히 제가 생성한 Form에서 발생한 Click에 EventHandler를 등록해야겠죠.
따라서 fm.Click에 EventHandler를 등록합니다.
EventHandler 등록시에는 주의할점이 단순히 등호(=)를 이용하는게아니라 += 또는 -= 기호를 사용해야합니다.
EventHandler에 등록할 동작은 하나보다 더 많을 수 있으므로 EventHandler를 추가한다는 개념이라고 이해하면 왜 += 기호를 쓰는지 이해가 쉬울겁니다.
Event처리의 흐름을 다시 정리해봅시다.
1. Event(클릭, 마우스 오버, 키보드 입력 등)가 발생한다
2. Event에 따른 처리를 한다.
User 입장에서 보이는 처리 방식은 위와 같습니다.
여기서 Event가 발생하는 곳을 소스(Source)라고 합니다.
Event가 발생하면 EventHandler라는 method가 처리를 합니다.
어떤 Event를 다루는지에 따라 사용되는 method나 class는 달라질 수 있어도 Event의 처리 흐름은 대체적으로 위와 같습니다.
개념 한가지를 더 알고갑시다.
fm.Click += new EventHandler(fm_event_click);
위 코드에서 EventHandler를 등록하는 부분은 위와 같았습니다.
근데 좀 이상합니다.
fm.Click이 발생하면 어떤 동작을 하도록 할당할건데 그러면 간단하게 fm.Click += fm_event_click() 으로 적으면 안될까요?
왜 굳이 Eventhandler에 제가 작성한 fm_event_click method를 담아서 fm.Click에 이벤트를 등록했을까요?
이것은 C#에서 Event 처리 시 사용하는 델리게이트(Delegate)라는 특징 떄문입니다.
위 코드에서 사용된 EventHandler가 델리게이트(Delegate)의 일종입니다.
EventHandler라는 Delegate도 이미 C# 내부에서 어떠한 일련의 코드로 정해져있습니다.
소스(Source)인 Form에서 클릭이 발생하면(fm.Click)
Form이 직접 fm_event_click method를 실행하는 것이 아닙니다.
클릭이 발생했을 때 fm은 EventHandler라는 델리게이트에 의뢰해서 fm_event_click method를 처리하는 방식입니다.
즉, fm.Click이 발생했을 때 fm이 처리해야할 fm_event_click method의 실행을 EventHandler라는 델리게이트에 위임해서 실행시키는 것이죠.
그래서 이름도 델리게이트(위임, Delegate) 입니다.
이렇게 하게되면 사용자가 프로그램을 사용하면서 발생할 수많은 이벤트 중 필요로 하는 이벤트가 등록된 EventHandler에 의뢰해서 Event method를 실행시키게 됩니다.
따라서 효율적인 처리를 할 수 있게 됩니다.
이번에는 버튼을 생성하고 버튼 클릭에 대한 Event를 만들어봅시다.
using System;
using System.Windows.Forms;
class MyProgram
{
public static void Main()
{
Form fm = new Form();
fm.Text = "Sample Window";
fm.Width = 300;
fm.Height = 200;
Label lbl = new Label();
lbl.Text = "Welcome!";
lbl.Parent = fm;
Button btn = new Button();
btn.Text = "Button";
btn.Top = lbl.Bottom;
btn.Width = lbl.Width;
btn.Parent = fm;
void btn_event_click(Object sender, EventArgs e)
{
lbl.Text = "Button clicked.";
}
btn.Click += new EventHandler(btn_event_click);
Application.Run(fm);
}
}
위 코드를 실행하면 아래와 같은 화면이 뜹니다. 버튼이 생겼죠.
그리고 버튼을 클릭하면 텍스트가 Button clicked.로 바뀝니다.
이전 예시와 거의 동일하니 차이가 있는 부분만 보겠습니다.
Button btn = new Button();
btn.Text = "Button";
btn.Top = lbl.Bottom;
btn.Width = lbl.Width;
btn.Parent = fm;
먼저 btn 객체 생성 부분입니다.
- Button btn = new Button();
버튼을 생성하려면 Button class를 이용하면 됩니다.
- btn.Text = "Button";
Button에 표시될 텍스트를 지정하는 부분입니다.
- btn.Top = lbl.Bottom;
btn.Top은 Button의 상단부분 위치를 정해줍니다.
저는 텍스트가 표시되는 lbl(Label)의 바로 아래에 Button을 표시할 것이므로 Label의 아래쪽 위치(lbl.Bottom)가 Button의 상단 위치가 되도록 하였습니다.
- btn.Width = lbl.Width;
btn.Width는 버튼의 가로길이를 의미합니다.
저는 Label의 가로길이(lbl.Width)와 동일하게 설정하였습니다.
- btn.Parent = fm;
버튼도 라벨처럼 당연히 소속관계를 명시해주어야합니다.
버튼도 제가 생성한 Window에 표시되게 할 것이므로 btn.Parent를 fm으로 설정해줍니다.
여기까지 버튼을 생성했으니 버튼 클릭에 대한 Event처리 부분을 봅시다.
void btn_event_click(Object sender, EventArgs e)
{
lbl.Text = "Button clicked.";
}
btn.Click += new EventHandler(btn_event_click);
이전에 봤던 예시와 완전히 동일합니다.
btn_event_click이라는 method를 선언하고 lbl.Text를 Button clicked.로 바꾸도록 method의 내용을 채워줍니다.
그리고 중요한 부분은 이번에 클릭이 발생할 Source는 Window(fm)가 아니라 버튼입니다.
따라서 btn.Click += ~~ 처럼 btn 객체의 Click에 이벤트를 등록합니다.
이때는 마찬가지로 btn_event_click method를 EventHandler 델리게이트에 등록합니다.
자 이제 Object sender라는 것에 대해 좀 더 자세히 알아봅시다.
아래 코드는 버튼이 클릭되었을 때 Event가 발생하게한 것은 완전히 동일합니다만, Object sender를 이용해보았습니다.
using System;
using System.Windows.Forms;
class MyProgram
{
public static void Main()
{
Form fm = new Form();
fm.Text = "Sample Window";
fm.Width = 300;
fm.Height = 200;
Label lbl = new Label();
lbl.Text = "Welcome!";
lbl.Parent = fm;
Button btn = new Button();
btn.Text = "Button";
btn.Top = lbl.Bottom;
btn.Width = lbl.Width;
btn.Parent = fm;
void btn_event_click(Object sender, EventArgs e)
{
Button btn_clicked = (Button)sender;
btn_clicked.Text = "Button clicked.";
lbl.Text = "Button clicked.";
}
btn.Click += new EventHandler(btn_event_click);
Application.Run(fm);
}
}
위 코드를 실행하면 아래와 같은 Window가 뜹니다.
그리고 버튼을 클릭해봅시다.
Button clicked.라고 텍스트가 바뀌었는데 이번에는 버튼에 표시되는 텍스트까지 Button clicked.로 바뀌었습니다.
Event method 부분을 봅시다.
void btn_event_click(Object sender, EventArgs e)
{
Button btn_clicked = (Button)sender;
btn_clicked.Text = "Button clicked.";
lbl.Text = "Button clicked.";
}
새로 추가된 부분은 아래 두 줄 입니다.
- Button btn_clicked = (Button)sender;
- btn_clicked.Text = "Button clicked.";
클릭이라는 이벤트가 발생한 객체는 바로 btn 객체입니다.
코드 윗부분에서 생성한 Button 객체이죠.
따라서 이 버튼이 클릭되면 btn_event_click method가 실행되는데 이때 Object sender라는 인자는 Event가 발생한 객체인 btn 객체를 받게 됩니다.
객체(Object) 타입의 sender라는 이름의 변수를 생성하고 그 변수에 Event가 발생한 객체인 btn 객체를 집어넣는것이죠.
- Object sender = btn;
마치 위 코드가 실행되는 것과 비슷합니다.
- Button btn = new Button();
근데 좀 이상합니다. btn 객체의 타입은 위 부분에서처럼 Button이라고 생성했었는데 sender의 타입은 그냥 객체(Object) 타입입니다.
그 이유는 수많은 Source 중 Event가 발생할 객체가 뭔지 미리 알 수 없기 때문에 어떤 객체에서 Event가 발생하건 sender라는 변수에 저장하기 위해 sender의 타입을 Object 타입으로 설정한 것입니다.
이러한 과정을 통해 method 내부에서는 parameter 중 하나인 sender를 사용할 수 있죠.
- Button btn_clicked = (Button)sender;
- btn_clicked.Text = "Button clicked.";
추가된 부분을 다시 보시면 sender는 btn 객체를 담고있을 것이지만 타입이 Object입니다.
따라서 (Button)sender 처럼 형 변환(Cast)을 해서 사용하게 됩니다.
그리고 이렇게 받은 btn_clicked 객체는 바로 btn 객체와 동일한 내용을 담고있고 btn_clicked 객체의 Text를 Button clicked.로 바꾸는 코드를 담은 것입니다.
사실 위 코드에서는 굳이 Object sender를 사용하지 않고 그냥 btn 객체에 직접 접근해도 됩니다.
method 내부에서 method 밖에 있는 객체에 접근하는 것은 가능하거든요.
근데 Object sender를 사용해야 편한 경우가 있습니다.
아래 예시를 봅시다.
우리는 프로그램의 메뉴창을 구성할겁니다.
이 메뉴 하나하나는 모두 객체로 구성되어있습니다.
그리고 어떤 메뉴가 클릭될 때 클릭된 메뉴를 표시해주는 코드를 작성했습니다.
using System;
using System.Windows.Forms;
class MyProgram
{
public static void Main()
{
Form fm = new Form();
fm.Width = 500;
fm.Height = 300;
Label lbl = new Label();
lbl.Parent = fm;
lbl.Width = 200;
lbl.Height = 20;
lbl.Dock = DockStyle.Bottom;
MenuStrip ms = new MenuStrip();
ms.Parent = fm;
ToolStripMenuItem menu_1 = new ToolStripMenuItem("Fruits");
ToolStripMenuItem menu_1_1 = new ToolStripMenuItem("Apple");
ToolStripMenuItem menu_1_2 = new ToolStripMenuItem("Banana");
ToolStripMenuItem menu_1_3 = new ToolStripMenuItem("Peach");
menu_1.DropDownItems.Add(menu_1_1);
menu_1.DropDownItems.Add(menu_1_2);
menu_1.DropDownItems.Add(menu_1_3);
ToolStripMenuItem menu_1_2_1 = new ToolStripMenuItem("Banana Size S");
ToolStripMenuItem menu_1_2_2 = new ToolStripMenuItem("Banana Size M");
ToolStripMenuItem menu_1_2_3 = new ToolStripMenuItem("Banana Size L");
menu_1_2.DropDownItems.Add(menu_1_2_1);
menu_1_2.DropDownItems.Add(menu_1_2_2);
menu_1_2.DropDownItems.Add(menu_1_2_3);
ToolStripMenuItem menu_2 = new ToolStripMenuItem("Vegetables");
ToolStripMenuItem menu_2_1 = new ToolStripMenuItem("Potato");
ToolStripMenuItem menu_2_2 = new ToolStripMenuItem("Carrot");
menu_2.DropDownItems.Add(menu_2_1);
menu_2.DropDownItems.Add(menu_2_2);
ms.Items.Add(menu_1);
ms.Items.Add(menu_2);
void menu_event_click(object sender, EventArgs e)
{
ToolStripMenuItem selected_menu = (ToolStripMenuItem)sender;
lbl.Text = selected_menu.Text;
}
menu_1.Click += new EventHandler(menu_event_click);
menu_1_1.Click += new EventHandler(menu_event_click);
menu_1_2.Click += new EventHandler(menu_event_click);
menu_1_2_1.Click += new EventHandler(menu_event_click);
menu_1_2_2.Click += new EventHandler(menu_event_click);
menu_1_2_3.Click += new EventHandler(menu_event_click);
menu_1_3.Click += new EventHandler(menu_event_click);
menu_2.Click += new EventHandler(menu_event_click);
menu_2_1.Click += new EventHandler(menu_event_click);
menu_2_2.Click += new EventHandler(menu_event_click);
Application.Run(fm);
}
}
위 코드를 실행하면 아래와 같은 Window가 뜹니다.
그리고 메뉴를 클릭해봅시다.
제가 클릭한 메뉴의 이름이 표시됩니다.
Event 부분을 봅시다.
void menu_event_click(object sender, EventArgs e)
{
ToolStripMenuItem selected_menu = (ToolStripMenuItem)sender;
lbl.Text = selected_menu.Text;
}
menu_1.Click += new EventHandler(menu_event_click);
menu_1_1.Click += new EventHandler(menu_event_click);
menu_1_2.Click += new EventHandler(menu_event_click);
menu_1_2_1.Click += new EventHandler(menu_event_click);
menu_1_2_2.Click += new EventHandler(menu_event_click);
menu_1_2_3.Click += new EventHandler(menu_event_click);
menu_1_3.Click += new EventHandler(menu_event_click);
menu_2.Click += new EventHandler(menu_event_click);
menu_2_1.Click += new EventHandler(menu_event_click);
menu_2_2.Click += new EventHandler(menu_event_click);
결국 우리는 Label의 Text(lbl.Text)를 선택된 메뉴의 Text로 바꾸는 코드를 작성해야합니다.
근데 무슨 메뉴가 선택될지 어떻게 알수있을까요?
모르죠.
이때 obejct sender를 이용합니다.
결국 클릭된 메뉴(Event가 발생한 메뉴)는 Object sender에 전달될 것이므로 object sender에 전달된 ToolStripMenuItem 객체를 selected_menu에 재할당해서 사용하는겁니다.
그러면 어떤 menu가 클릭될지 일일이 조건문으로 작성해줄 필요가 없죠.
만약 메뉴 관련 내용을 모른다면 아래 글을 참고하면 이해가 빠릅니다.
https://cosmosproject.tistory.com/561
이번에는 마우스의 위치를 이용한 이벤트를 작성해봅시다.
예를들어 마우스가 Form 안에 들어오면 글자를 어떻게 바꾸고 마우스 커서가 Form 밖으로 나가면 글자를 어떻게 바꾸고 이러한 이벤트입니다.
using System;
using System.Windows.Forms;
class MyProgram
{
public static void Main()
{
Form fm = new Form();
fm.Text = "Sample Window";
fm.Width = 300;
fm.Height = 200;
Label lbl = new Label();
lbl.Text = "Welcome!";
lbl.Parent = fm;
void fm_mouse_in(Object sender, EventArgs e)
{
lbl.Text = "Mouse in";
}
void fm_mouse_out(Object sender, EventArgs e)
{
lbl.Text = "Mouse out";
}
fm.MouseEnter += new EventHandler(fm_mouse_in);
fm.MouseLeave += new EventHandler(fm_mouse_out);
Application.Run(fm);
}
}
위 코드를 실행해봅시다.
가장 먼저 위같은 창이 뜹니다.
그리고 마우스 커서를 윈도우 안쪽으로 가져다두면 위처럼 Mouse in이라고 텍스트가 바뀝니다.
마우스 커서를 윈도우 밖으로 내보내면 Mouse out이라고 텍스트가 바뀌게 됩니다.
마찬가지로 기본적인 형태는 동일합니다만 Mouse over의 이벤트 처리가 다릅니다.
아래 부분을 봅시다.
void fm_mouse_in(Object sender, EventArgs e)
{
lbl.Text = "Mouse in";
}
void fm_mouse_out(Object sender, EventArgs e)
{
lbl.Text = "Mouse out";
}
fm.MouseEnter += new EventHandler(fm_mouse_in);
fm.MouseLeave += new EventHandler(fm_mouse_out);
먼저 마우스 커서가 들어와있을 때와 나가있을 때의 동작을 담을 method를 생성합니다.
fm_mouse_in method는 마우스가 Window에 들어왔을 때 실행될 method로서 작성하였고,
fm_mouse_in method는 마우스가 Window로부터 나가있을 때 실행될 method로서 작성하였습니다.
그리고 생성한 method를 EventHandler에 등록합니다.
근데 Mouse 클릭이 아니라 Mouse가 들어왔다가 나갈때를 의미하므로
fm.MouseEnter와 fm.MouseLeave에 method를 등록해야합니다.
fm.MouseEnter는 마우스 커서가 fm(Form)에 들어왔을 때를 의미합니다.
fm.MouseLeave는 마우스 커서가 fm(Form)으로부터 나갔을 때를 의미합니다.
using System;
using System.Windows.Forms;
class MyProgram
{
public static void Main()
{
Form fm = new Form();
fm.Text = "Sample Window";
fm.Width = 300;
fm.Height = 200;
Label lbl = new Label();
lbl.Text = "Welcome!";
lbl.Parent = fm;
Button btn = new Button();
btn.Text = "Button";
btn.Top = lbl.Bottom;
btn.Width = lbl.Width;
btn.Height = lbl.Height;
btn.Parent = fm;
void btn_mouse_in(Object sender, EventArgs e)
{
btn.Text = "Mouse in button";
}
void btn_mouse_out(Object sender, EventArgs e)
{
btn.Text = "Mouse out of button";
}
btn.MouseEnter += new EventHandler(btn_mouse_in);
btn.MouseLeave += new EventHandler(btn_mouse_out);
Application.Run(fm);
}
}
이러한 MouseEnter, MouseLeave Event는 버튼에도 적용할 수 있습니다.
위 코드를 실행해보면 버튼에 마우스를 오버할때와 아닐 때 버튼에 표시되는 텍스트가 달라지는 것을 볼 수 있습니다.
'C# > C#' 카테고리의 다른 글
C# : enum (Enumeration, 열거체) (0) | 2022.04.01 |
---|---|
C# : KeyEventHandler (키보드 입력 이벤트, Keyboard input event, KeyDown, KeyUp) (0) | 2022.03.30 |
C# : static (정적 데이터) (0) | 2022.03.29 |
C# : abstract, virtual (class template 생성하기) (0) | 2022.03.23 |
C# : array (0) | 2022.03.23 |