본문 바로가기

문과 코린이의, [C#] 기록/C# 이론

[문과 코린이의 IT 기록장] C# - C# 프로그램 구조(Visual Studio C# 구성, C# 프로젝트, 클래스와 인스턴스, 메서드(함수) 선언, 클래스 생성자, 클래스 프로퍼티(속성))

반응형

[문과 코린이의 IT 기록장] C# - C# 프로그램 구조(Visual Studio C# 구성, C# 프로젝트, 클래스와 인스턴스, 메서드(함수) 선언, 클래스 생성자, 클래스 프로퍼티(속성))

[문과 코린이의 IT 기록장] C# - C# 프로그램 구조(Visual Studio C# 구성, C# 프로젝트, 클래스와 인스턴스, 메서드(함수) 선언, 클래스 생성자, 클래스 프로퍼티(속성))

 


 

C# 프로그래밍 기초 - 인프런 | 강의

본 강좌는 C# 문법 위주로 구성되어있지 않습니다. 클래스를 이해하고 만드는 요령 위주로 구성되어 있습니다. 기초 문법도 다루지만 많은 예제를 가지고 진행하기 때문에 프로그램 실전 작성

www.inflearn.com


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("나는 학생 클래스 입니다.");            
        }
    }
}

 

* 유의사항
- 아직 공부하고 있는 문과생 코린이가, 정리해서 남겨놓은 정리 및 필기노트입니다.
- 정확하지 않거나, 틀린 점이 있을 수 있으니, 유의해서 봐주시면 감사하겠습니다.
- 혹시 잘못된 점을 발견하셨다면, 댓글로 친절하게 남겨주시면 감사하겠습니다 :)
반응형