[문과 코린이의 IT 기록장] C# - C# 프로그램 구조(Visual Studio C# 구성, C# 프로젝트, 클래스와 인스턴스, 메서드(함수) 선언, 클래스 생성자, 클래스 프로퍼티(속성))
0. Visual Studio C# 구성
c# 은 가장 위에 솔루션을 가지고 있으며, 하나의 솔루션은 여러 프로젝트를 가질 수 있음.
하나의 프로젝트는 여러개의 .cs(C# 소스파일)을 가질 수 있다.
* Solution > Project > .CS > Class > Method > .연산자로 하위 객체에 접근
* 솔루션(Solution) 만들 때, Net Core로 만들기. .Net Framework로 만들면, 콘솔(f5) 실행시 창이 꺼짐.
1. C# 프로젝트
- 프로젝트는 하나 이상의 .cs파일로 구성된다.
- 프로젝트를 컴파일한 결과물은, 크게 두 가지 형태로 구분된다.
a. main()함수를 가지고 있는 프로젝트는, .exe파일로 결과를 생성한다.
b. .main()함수가 없는 프로젝트는, .DLL파일로 라이브러리 파일을 생성한다.
* DLL : 재사용 가능한 클래스들을 잔뜩 몰아놓은 라이브러리
* 어떤 exe파일은 DLL파일과 더불어서, 파일들을 가져다 쓰기도 함.
* .EXE와 .DLL파일은 어셈블리어라고 칭한다.
2. 클래스와 인스턴스
1) 클래스
- 클래스 : 실세계에 존재하는 사물 또는 개념을 모델링한 것. C#에서는 타입이라고 한다.
ex. 붕어빵 틀 , 설계도면
=> 우리가 프로그램 짠 코드는 클래스라고 함.
[ 선언 ]
접근제한자 class 클래스명
{
속성 정의; // property (속성)
행위 정의; // method (행위)
}
- 클래스는 하나의 .cs(C#소스파일)파일에, 하나 이상 선언할 수 있다.
* 그러나 유지보수 등, 여러 이유로, 원칙적으로 하나의 C#파일은, 하나의 클래스를 갖는 것을 원칙으로 한다.
ex.
class HelloWorld // C# 소스파일명과 클래스명과 같은 이름으로 만들어짐 (Hello World 파일 내, Hello World 메서드가 존재)
{
// C#에서는 하나 이상의 메소드를 꼭 정의해줘야 한다는, 규약이 있음. (그 클래스는 main)
// 이 이외는 마음대로 메서드를 만들어도 아니어도 됨.
static void Main()
{
System.Console.WriteLine("Hello World"); // 해당 문자열 출력 + enter
}
}
- System : 라이브러리.
* ctrl+.을 누르면, System이라고 이름붙여준 어셈블리를 앞으로 쓸 것이라고 선언해줄 수 있음 ex. Using System
- System 라이브러리(namespace) 내, Console이라는 클래스에, WriteLine이라는 메서드가 존재함.
2) 인스턴스
- 인스턴스 : 클레스가 타입을오 사용되어, 프로그램에서 실행될 수 있도록 준비된 상태.
ex. 만들어진 붕어빵 그 자체 , 각각의 집
=> 컴퓨터 메모리상에 나타난 클래스가, 실제로 움직일 수 있는 코드로서 나타남. 클래스로 인스턴스를 3개 만들면, 서로 다른 메모리 영역에 3개의 인스턴스가 나타남.
3. 메서드(함수) 선언
- 모든 실행문(명령문)은 메서드에서만 실행 가능하다.
- 객체의 로직을, 명령문으로 구현한다.
- 메서드는 함수, 서브루틴, 프로시저라고도 불린다.
- 메서드는 다른 메서드에서 호출되는 형식으로 사용된다.
- 메서드는 C언어와 동일하게 재사용된다.
- 다른 클래스에 있는 메서드 호출은, 클래스_인스턴스_변수.메서드명(파라미터)방식으로 호출한다.
- 같은 클래스에 있는 메서드는, 메서드명(파라미터)로 호출한다.
1) 메서드가 값을 반환하지 않는 경우
접근제한자 void 메서드명([타입명][매개변수명], ...)
{
[return;]
}
2) 메서드가 값을 반환하는 경우
접근제한자 반환타입 메서드명([타입명] [매개변수명], ...)
{
return 반환타입;
}
ex 1.
using System;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
PrintHello();
}
static void PrintHello()
{
Console.WriteLine("Hello World");
}
}
}
ex 2.
using System;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
PrintHello("Hello World");
}
static void PrintHello(string str)
{
Console.WriteLine(str);
}
}
}
ex 3.
using System;
class Program
{
static void Main(string[] args)
{
AA var = new AA(); // AA 클래스에 대한, var 인스턴스 생성
var.PrintHello("PrintHello Go");
// 다른 클래스에 있는 메서드 호출을, 인스턴스.메서드명 방식으로 호출
}
}
class AA // 클래스 선언
{
public void PrintHello(string str)
{
Console.WriteLine(str);
}
}
4. 클래스 생성자
- 클래스 인스턴스가 만들어질 때, 자동으로 불려지는 메서드
- 반환 타입이 없다.
- 클래스 이름과 생성자 메서드 이름이 동일해야 한다.
- 메서드 오버로딩이 가능하다. (오버로딩 : 파라미터를 다르게 해서 여러개 만들 수 있다)
- 클래스 차원의 파라미터를 받아들일 수 있다.
- 대부분 초기화 목적으로 사용된다.
ex 1.
[ Program.cs ]
using System;
using consoleapp3; // Consoleapp3 namepsace에 있는, 클래스를 사용하기 위해 불러옴.
namespace ConsoleAPP2 // 보통 프로젝트명과 namespace를 일치시켜주고, cs파일명과 그 내의 클래스명을 일치시켜준다.
{
class Program
{
static void Main(string[] args) // Main함수는 main이라고 쓰면 안된다.
{
Student student = new Student(); // 내로컬에 있는듯이, Consoleapp3 namespace의 student클래스를 사용할 수 있다.
// student 인스턴스 생성
}
}
}
[ student.cs ]
using System;
using System.Collections.Generic;
using System.Text;
namespace consoleapp3
{
// summar : 어디 소속 클래스인지 클래스에 마우스를 가져다되면, 설명이 나올 수 있도록 사용하는 것
/// <summary>
/// <para>ConsoleAPP2.Student 클래스 정의</para>
/// <para>이것은 테스트입니다.</para>
/// </summary>
public class Student // 하나의 namespace 내에서는, 중복된 클래스가 존재하면 안된다. (namespace가 다르면 상관없음)
{
public Student() // 생성자 호출
{
Console.Write("생성자 호출");
}
}
}
ex 2.
- 즉 생성자는 인스턴스가 만들어질 때, 딱 한번만 불러진다
[ Program.cs ]
using System;
using consoleapp3; // Consoleapp3 namepsace에 있는, 클래스를 사용하기 위해 불러옴.
namespace ConsoleAPP2 // 보통 프로젝트명과 namespace를 일치시켜주고, cs파일명과 그 내의 클래스명을 일치시켜준다.
{
class Program
{
static void Main(string[] args) // Main함수는 main이라고 쓰면 안된다.
{
// st1 인스턴스 생성
Student st1 = new Student("홍길동"); // 내로컬에 있는듯이, Consoleapp3 namespace의 student클래스를 사용할 수 있다.
st1.printname();
}
}
}
[ student.cs ]
using System;
using System.Collections.Generic;
using System.Text;
namespace consoleapp3
{
// summar : 어디 소속 클래스인지 클래스에 마우스를 가져다되면, 설명이 나올 수 있도록 사용하는 것
/// <summary>
/// <para>ConsoleAPP2.Student 클래스 정의</para>
/// <para>이것은 테스트입니다.</para>
/// </summary>
public class Student // 하나의 namespace 내에서는, 중복된 클래스가 존재하면 안된다. (namespace가 다르면 상관없음)
{
private string name;
public Student() // 생성자 호출 ex. Stduent()로 호출
{
Console.Write("생성자 호출");
}
public Student(string name) // 파라미터 타입에 따라, 같은 이름의 다른 생성자 호출 가능 ex. Student(string)으로 호출 가능
{
this.name = name; // 매개변수로 가져오는 name변수의 값을, this.name에 저장한다.
// this.name은 위의 private string name
}
public void printname()
{
Console.WriteLine("name = " + name);
}
}
}
ex 3.
- C#에서 자기가 자신쪽의 생성자를 부르는 구문. (생성자 코드 작성에 있어, 중복을 제거해 단순하게 코드 작성)
[ Program.cs ]
using System;
using consoleapp3; // Consoleapp3 namepsace에 있는, 클래스를 사용하기 위해 불러옴.
namespace ConsoleAPP2 // 보통 프로젝트명과 namespace를 일치시켜주고, cs파일명과 그 내의 클래스명을 일치시켜준다.
{
class Program
{
static void Main(string[] args) // Main함수는 main이라고 쓰면 안된다.
{
Student st1 = new Student();
// 1. Student()에서 Student(name)호출, Student(name)에서 Student(name, address)호출
// 2. Student(name,address)의 내용들을 모두 실행 한 후, return, 이후 Student(name)에서 내용 실행한 후 return, 마지막으로 Student()에서 내용 실행한 후 return
Student st2 = new Student("홍길동");
Student st3 = new Student("홍길동","서울특별시");
}
}
}
[ Stduent.cs ]
using System;
using System.Collections.Generic;
using System.Text;
namespace consoleapp3 {
public class Student // 하나의 namespace 내에서는, 중복된 클래스가 존재하면 안된다. (namespace가 다르면 상관없음)
{
private string name;
private string address;
// C#에서 자기가 자신쪽의 생성자를 부르는 구문. (생성자 코드 작성에 있어, 중복을 제거해 단순하게 코드 작성)
public Student(string name, string address) // 최종적으로 여기서 생성자가 실행됨.
{
this.name = name;
this.address = address;
Console.WriteLine("생성자(name, addreess) 생성 완료");
}
public Student(string name) : this(name, null) // 자신의 생성자를 부르는데(this), 파라미터가 두개인 생성자에, name과 null값을 전달해 호출한다.
{
Console.WriteLine("생성자(name) 생성 완료");
}
public Student() : this(null) // 자신의 생성자를 부르는데(this), 파라미터가 하나인 생성자에 null값을 전달하여 호출한다.
{
Console.WriteLine("생성자() 생성 완료");
}
}
}
5. 클래스 프로퍼티(속성)
ex 1.
[ Program.cs ]
using System;
using consoleapp3;
namespace ConsoleAPP2
{
class Program
{
static void Main(string[] args) // Main함수는 main이라고 쓰면 안된다.
{
Student st1 = new Student();
// 2.private임에도, 할 수 있는 방법 : public 메서드를 사용해서 접근하고, 이를 거쳐 private에 접근할 수 있도록 함.
st1.SetName("홍길동");
System.Console.WriteLine(st1.GetName());
}
}
}
[ student.cs ]
using System;
using System.Collections.Generic;
using System.Text;
namespace consoleapp3 {
public class Student
{
// name을 외부에 보여주며, 외부에서 설정할 수 있도록 하는 방법
// 1. private -> public으로 변경
// 2. private임에도, 할 수 있는 방법 : public 메서드를 사용해서 접근하고, 이를 거쳐 private에 접근할 수 있도록 함.
private string name;
private string address;
/// <summary>
/// getter of name
/// </summary>
/// <returns></returns>
public string GetName() // 변수, 메서드 대문자, 소문자 분류됨.
{
return name; // private name은 노출되지 않고 숨어있으면서, 본인의 값만 return해줌
}
/// <summary>
/// setter of name
/// </summary>
/// <param name="name"></param>
public void SetName(string name)
{
this.name = name; // name은 노출되지 않으면서, 입력한 값을 인스턴스 변수에 저장함.
}
}
}
ex 2.
- private 클래스 변수 + getter(), Setter() 메서드 사용 vs pulic 클래스 변수 사용
: private 클래스 변수 + getter(), Setter()는, 메서드로 들어오는 파라미터를 검증해서, 사전에 오류를 차단할 수 있다.
: 그러나 public 클래스 변수를 사용할 때는, 잘못된 값이 입력되더라도, 논리적으로 문제만 없다면 오류 차단이 불가능하다.
- 이러한 이유로, 일반적으로 클래스의 속성은 private로 막고, 클래스 내부 메서드를 통해 private 변수에 접근할 수 있도록 하는 것이, C# OOP의 원칙이며, 이 방법이 주로 사용된다.
[ Program.cs ]
using System;
using consoleapp3;
namespace ConsoleAPP2
{
class Program
{
static void Main(string[] args) // Main함수는 main이라고 쓰면 안된다.
{
Student st1 = new Student();
st1.SetName("홍길동");
// 코드의 로직으로는 문제가 없는 구문들. but 사용에 잇어 문제가 발생하는 구문들
// 1. private 변수로 선언해놓고, 함수를 통해 제한을 걸어, 문제 해결 O
st1.SetAge(1000); // 0을 더 넣어서, 값을 잘못 입력할 경우
st1.SetAge(-1); // -값으로 잘못 입력할 경우
// 2. public 변수로 선언해, 직접 값을 대입하는 방법으로, 문제 해결 방법이 X
st1.age = 10000; // 이는 코드로 막을 방법이 없음. 그냥 실수인 값도 저장되는 것.
}
}
}
[ Student.cs ]
using System;
using System.Collections.Generic;
using System.Text;
namespace consoleapp3 {
public class Student
{
private string name;
private string address;
public int age;
public string GetName() // 변수, 메서드 대문자, 소문자 분류됨.
{
return name; // private name은 노출되지 않고 숨어있으면서, 본인의 값만 return해줌
}
public void SetName(string name)
{
this.name = name;
}
/// <summary>
/// getter of name
/// </summary>
/// <returns></returns>
public int GetAge() // 변수, 메서드 대문자, 소문자 분류됨.
{
return age; // private name은 노출되지 않고 숨어있으면서, 본인의 값만 return해줌
}
/// <summary>
/// setter of name
/// </summary>
/// <param name="name"></param>
public void SetAge(int age)
{
if (age < 0 || age > 121)
{
Console.WriteLine("나이는 음수나 120세를 넘을 수 없습니다.");
return;
}
this.age = age;
}
}
}
ex 3.
- 위의 getter(), setter()를 축약해서 사용하는 방법
ps. 인스턴스.
* 파란색 박스 : 필드
* 나사 조이는것 처럼 생긴 모양 : 프로퍼티
* 정육면체 : 메서드
[ program.cs ]
using System;
using consoleapp3;
namespace ConsoleAPP2
{
class Program
{
static void Main(string[] args) // Main함수는 main이라고 쓰면 안된다.
{
Student st1 = new Student();
// 프로퍼티 getter 사용
st1.Name = "홍길동"; // SetName()을 사용한 것처럼, 파라미터를 받아들여서 설정하는 것 아님.
// 프로퍼티 setter 사용
System.Console.WriteLine(st1.Name);
}
}
}
[ student.cs ]
using System;
using System.Collections.Generic;
using System.Text;
namespace consoleapp3 {
public class Student
{
private string address;
public int age;
// 과거에는 변수 : 소문자로 작성 , 프로퍼티 작성 : 대문자로 작성함. (네이밍, 작명의 문제)
// 이 문제를 해결하기 위해, 하나의 이름을 프로퍼티 + 변수명으로 다 쓸 수 있도록 문법을 바꿔, 컴파일러가 알아서 인식하고 변하게 만듬
/* public string Name // 프로퍼티 선언 (이는 변수이면서, 프로퍼티의 역할을 함)
{
// 이렇게 작성해도, 컴파일 타임 때, 위의 GetName(), SetName()과 같이 만들어줌
get { return name; }
set { name = value; }
}
*/
// prop + tab + tab => 프로퍼티 형식이 생성
public string Name{ get; set; } // 위를 더 줄인 방식. (읽기/쓰기 전용)
// public string Name { get; } // (읽기전용)
}
}
6. static 클래스
- 인스턴스는 static 클래스를 부를 수 있지만, 그 역은 성립하지 않는다.
- static 클래스는, static 클래스끼리만 소통한다.
ex. 아래의 예제에서, Program Class 내부에서, static main클래스가 static student를 부를 수 있음.
- static은 한번 메모리 공간을 차지하면, 끝까지 없어지지 않기 때문에, 현명하게 사용해야 한다.
- 인스턴스는 사용하지 않을 시, 가비지 컬렉터가 해당 메모리를 해제하게 된다. 따라서 인스턴스를 적절하게 현명히 사용하는 것이 중요하다.
ex.
[ Program.cs ]
using System;
namespace StudentManagement
{
class Program
{
static void Main(string[] args)
{
Student.WhoAreYou();
}
}
static class Student
{
static public void WhoAreYou() // static을 붙여야 함.
{
// cw + tab + tab : Console.WriteLine
Console.WriteLine("나는 학생 클래스 입니다.");
}
}
}
* 유의사항 - 아직 공부하고 있는 문과생 코린이가, 정리해서 남겨놓은 정리 및 필기노트입니다. - 정확하지 않거나, 틀린 점이 있을 수 있으니, 유의해서 봐주시면 감사하겠습니다. - 혹시 잘못된 점을 발견하셨다면, 댓글로 친절하게 남겨주시면 감사하겠습니다 :) |