[220305] HelloWorld 콘솔 앱으로 찍기 / 이론
Visual Studio > 새 프로젝트 만들기 > 콘솔 앱(.NET Framework) >
프로젝트 이름 : HelloWorld
위치 : C:\DotNet
솔루션 이름 : HelloWorld
> 만들기
HelloWorld.cs
using System;
//c# 무조건 대소문자 구별, 하나의 시작 프로젝트에는 하나의 메인 메서드만
class HelloWorld
//클래스이름과 파일명을 굳이 매치 시킬 필요 없다. 하나의 cs 파일에는 수백개의 class 넣을 수 있다.
//심지어 클래스 이름이 한글이어도 됨
{
static void Main(string[] args)
{
System.Console.WriteLine("HelloWorld");
//(시스템생략권장)시스템 네임스페이스 안에있는 콘솔 클래스 안에 있는 WriteLine메서드 사용
Console.ReadLine();
}
}
Ctrl + F5 로 실행
솔루션 탐색기 > (솔루션 HelloWord 우클릭 > 솔루션 빌드) 또는
(HelloWorld 프로젝트파일 우클릭 > 빌드) : 빌드는 컴파일을 의미, Windows 운영체제이므로 빌드 시 exe 파일로 만들어진다.
HelloWorld 프로젝트파일 우클릭 > 탐색기에서 열기 >
bin > debug > HelloWorld.exe 클릭하면 실행 될 듯 하다가 꺼짐
파일 경로에 cmd 입력 > dir 작성 > H 치고 탭키 누르면 HelloWorld.exe 작성 됨
(가장 처음의 실행파일 자동 작성) > 엔터 누르면 실행된다.
C# 이론
struck : 구조체 (서로 다른 데이터 형식을 하나의 이름으로 묶어서 관리)
enum : 열거형 (상수들을 하나의 이름으로 열거해서 기억)
클래스 - 구조체와 열거형의 기능을 다 가지고 있음
static 변수 : 함수가 실행될 때 딱 한 번만 초기화 되고 함수가 종료되더라도 올라간 메모리 공간에서 그 값을 유지.
yield : 호출자(Caller)에게 컬렉션 데이타를 하나씩 리턴할 때 사용한다. 흔히 Enumerator(Iterator)라고 불리우는 이러한 기능은 집합적인 데이타셋으로부터 데이타를 하나씩 호출자에게 보내주는 역할을 한다.
yield는 yield return 또는 yield break의 2가지 방식으로 사용되는데, (1) yield return은 컬렉션 데이타를 하나씩 리턴하는데 사용되고, (2) yield break는 리턴을 중지하고 Iteration 루프를 빠져 나올 때 사용한다.
예제
using System;
using System.Collections.Generic;
class Program
{
static IEnumerable<int> GetNumber()
{
yield return 10; // 첫번째 루프에서 리턴되는 값
yield return 20; // 두번째 루프에서 리턴되는 값
yield return 30; // 세번째 루프에서 리턴되는 값
}
static void Main(string[] args)
{
foreach (int num in GetNumber())
{
Console.WriteLine(num);
}
}
}
이러한 특별한 리턴 방식은 다음과 같은 경우에 유용하게 사용된다.
(1) 만약 데이타의 양이 커서 모든 데이타를 한꺼번에 리턴하는 것하는 것 보다 조금씩 리턴하는 것이 더 효율적일 경우. 예를 들어, 어떤 검색에서 1만 개의 자료가 존재하는데, UI에서 10개씩만 On Demand로 표시해 주는게 좋을 수도 있다. 즉, 사용자가 20개를 원할 지, 1000개를 원할 지 모르기 때문에, 일종의 지연 실행(Lazy Operation)을 수행하는 것이 나을 수 있다.
(2) 어떤 메서드가 무제한의 데이타를 리턴할 경우. 예를 들어, 랜덤 숫자를 무제한 계속 리턴하는 함수는 결국 전체 리스트를 리턴할 수 없기 때문에 yield 를 사용해서 구현하게 된다.
(3) 모든 데이타를 미리 계산하면 속도가 느려서 그때 그때 On Demand로 처리하는 것이 좋은 경우. 예를 들어 소수(Prime Number)를 계속 리턴하는 함수의 경우, 소수 전체를 구하면 (물론 무제한의 데이타를 리턴하는 경우이기도 하지만) 시간상 많은 계산 시간이 소요되므로 다음 소수만 리턴하는 함수를 만들어 소요 시간을 분산하는 지연 계산(Lazy Calculation)을 구현할 수 있다.
- ?? 연산자는 Null-coalescing operator (널 병합 연산자)
a = b ?? 0; 이라고 하면 b 가 null 이 아닐 때는는 b 값을 a 에 할당하고 b 가 null 이면 ?? 다음 값 즉 0 을 a 에 할당하는 연산자
- 값형식과 참조형식
C#의 데이터 형식은 크게 값형식과 참조형식으로 나뉜다. 이 차이점은 이들 형식이 복사되는 방식에 따라 나뉘게 된다.
값형식의 데이터는 항상 값으로 복사되지만, 참조형식 데이터는 항상 참조로 복사된다.
값형식 | 참조형식 | |
저장위치 | 스택 | 힙 메모리 |
할당된 곳에 저장되는 데이터 | 입력한 데이터 | 데이터가 위치한곳의 참조 |
특징 | 해당 메소드 실행이 종료되면 사라짐 int a = 1; int b = a; 위의 a,b의 값중 어느 하나의 값을 수정해도 다른쪽에는 영향을 끼치지 않는다 |
GC에 의해 정리됨. 서로 다른 두 변수가 같은 데이터를 참조한다면 한개의 변수값을 변경하면 다른 변수도 영향을 받는다. |
변환 | 값형식 -> 참조형식 Boxing |
참조형식 -> 값형식 UnBoxing |
복사 | 얕은복사 | 깊은복사 |
예 | bool, char, byte, decimal, double, enum, float, int long, short, sbyte, struct, uint, ulong, ushort | class, interface, delegate, object, string |
static void Main(string[] args)
{
// ref 사용. 초기화 필요.
int x = 1;
double y = 1.0;
double ret = GetData(ref x, ref y);
Console.WriteLine(ret);
// out 사용. 초기화 불필요.
int c, d;
bool bret = GetData(10, 20, out c, out d);
Console.WriteLine(bret);
}
- 접근제한자
https://blog.hexabrain.net/140
기본값은 private입니다.
접근제한자는 클래스, 변수, enum, 함수 앞에 적어주게 되고, 선언된 접근제한자의 영향을 받습니다.
1. public
public으로 선언된다면 어느 곳에서든 자유롭게 사용될 수 있습니다. 아무런 제한을 받지 않고 원하는 곳에서 사용됩니다.
2. private
private으로 선언되면 약간의 제한을 갖게 됩니다. 예를 들어 어떤 클래스에 변수들이 private으로 선언된 경우 해당 클래스에서만 접근이 가능합니다.
3. internal
internal로 선언된다면 해당 프로젝트에 public처럼 사용됩니다. 자신의 프로젝트에서 내부적으로 사용된다는 뜻이죠. 이는 외부에서 사용될 가능성이 있는 프로젝트에서 유용하게 사용됩니다. 해당 프로젝트의 사용자가 굳이 몰라도 되는 정보를 감추는 것이죠. 클래스를 생성할 경우 아무런 접근제한자를 선언하지 않았다면, 기본값은 internal 입니다.
4. protected
protected로 선언된다면 상속받은 자식의 클래스에서만 사용 가능한 제한을 갖습니다.
접근제한자를 잘 고려해서 프로그램을 만든다면 코드를 구조화하고 체계적으로 정리할 수 있는 장점이 있습니다. 개인적으로 접근제한자는 항상 명시적으로 선언해주는 습관을 가지면 좋다고 생각해요.
https://math-development-geometry.tistory.com/5
- 어셈블리
C#에서 컴파일된 소스 코드의 결과를 닷넷 어셈블리라고 합니다.
Dictionary<TKey,TValue> 클래스 : 키와 값의 컬렉션을 나타냅니다.
네임스페이스:System.Collections.Generic
어셈블리:System.Collections.dll
- 제네릭
클래스의 거의 모든 부분이 동일한데 일부 데이타 타입만이 다른 경우가 있을 수 있다. 예를 들어, 사칙연산을 하는 클래스 A가 있다고 가정하자. 이 클래스 A에는 int 타입의 필드들이 있고, int 타입을 파라미터로 받아 계산하는 메서드들도 있다. 그러면 이 클래스 A를 double 타입의 데이타를 가지고 사용할 수 있을까? 그렇 수 없다. 왜냐하면 이미 모든 필드 및 파라미터가 int로 설정되어 있기 때문이다.
이런 경우 C#의 제네릭 타입(Generic Type)을 사용할 수 있는데, 제네릭 타입에서는 int, float, double 같은 데이타 요소 타입을 확정하지 않고 이 데이타 타입 자체를 타입파라미터(Type Parameter)로 받아들이도록 클래스를 정의한다. 이렇게 정의된 클래스 즉 C# 제네릭 타입을 사용할 때는 클래스명과 함께 구체적인 데이타 타입을 함께 지정해 주게 된다. 이렇게 하면 일부 상이한 데이타 타입 때문에 여러 개의 클래스들을 따로 만들 필요가 없어지게 된다. C# 제네릭은 이렇게 클래스 이외에도 인터페이스나 메서드에도 적용될 수 있다.
요약하면, C# 제네릭은 C++의 템플릿과 비슷한 (주: 내부 아키텍쳐는 상당한 차이점이 있다) 개념으로서 클래스, 인터페이스, 메서드 등에 <T> 같은 타입 파라미터를 붙여 구현한다. 사용시에는 이 타입 파라미터에 특정 타입을 지정하게 되는데, 실행(Runtime)시에 제네릭 타입(Generic Type)으로부터 지정된 타입의 객체(object)를 구체적으로 생성해서 사용하게 된다. 타입 파라미터는 하나 이상 여러 개를 지정할 수도 있다.
https://www.csharpstudy.com/CSharp/CSharp-generics.aspx
제네릭 타입 제약 (Type Constraint)
예제
// T는 Value 타입
class MyClass<T> where T : struct
// T는 Reference 타입
class MyClass<T> where T : class
// T는 디폴트 생성자를 가져야 함
class MyClass<T> where T : new()
// T는 MyBase의 파생클래스이어야 함
class MyClass<T> where T : MyBase
// T는 IComparable 인터페이스를 가져야 함
class MyClass<T> where T : IComparable
// 좀 더 복잡한 제약들
class EmployeeList<T> where T : Employee,
IEmployee, IComparable<T>, new()
{
}
// 복수 타입 파라미터 제약
class MyClass<T, U>
where T : class
where U : struct
{
}
- 속성(C# 프로그래밍 가이드)
속성은 전용 필드의 값을 읽거나 쓰거나 계산하는 유연한 메커니즘을 제공하는 멤버입니다. 공용 데이터 멤버인 것처럼 속성을 사용할 수 있지만, 실제로 접근자라는 특수 메서드입니다. 이렇게 하면 데이터에 쉽게 액세스할 수 있으며 메서드의 안전성과 유연성 수준을 올리는 데에도 도움이 됩니다.
필드와 달리 속성은 변수로 분류되지 않습니다. 따라서 ref 또는 out 매개 변수로 속성을 전달할 수 없습니다.
- 속성을 사용하면 클래스가 구현 또는 검증 코드를 숨기는 동시에 값을 가져오고 설정하는 방법을 공개적으로 노출할 수 있습니다.
- get 속성 접근자는 속성 값을 반환하는 데 사용되고 set 속성 접근자는 새 값을 할당하는 데 사용됩니다. C# 9 이상에서는 개체 생성 중에만 새 값을 할당하는 데 init 속성 접근자가 사용됩니다. 이러한 접근자는 각기 다른 액세스 수준을 가질 수 있습니다. 자세한 내용은 접근자 액세스 가능성 제한을 참조하세요.
- value 키워드는 또는 init 접근자가 할당하는 값을 정의하는 데 사용됩니다.
- 속성은 읽기/쓰기( 및 set 접근자 모두 포함), set(get 접근자는 포함하지만 set 접근자는 포함 안 함) 또는 get(set 접근자는 포함하지만 get 접근자는 포함 안 함)일 수 있습니다. 쓰기 전용 속성은 거의 없으며 주로 중요한 데이터에 대한 액세스를 제한하는 데 사용됩니다.
- 사용자 지정 접근자 코드가 필요 없는 단순한 속성은 식 본문 정의나 자동 구현 속성으로 구현할 수 있습니다.
-> prop + tab + tab
속성은 필드의 액세스 수준, 속성 형식, 속성 이름, get 접근자 및/또는 set 접근자를 선언하는 코드 블록을 차례로 지정하여 클래스 블록에서 선언됩니다.
public class Date
{
private int _month = 7; // Backing store
public int Month
{
get => _month;
set
{
if ((value > 0) && (value < 13))
{
_month = value;
}
}
}
}
이 예제에서 Month는 속성으로 선언되었으므로, set 접근자를 통해 Month 값이 1에서 12 사이로 설정되도록 할 수 있습니다. Month 속성은 전용 필드를 사용하여 실제 값을 추적합니다. 속성 데이터의 실제 위치를 종종 속성의 "백업 저장소"라고 합니다. 속성은 프라이빗 필드를 백업 저장소로 사용하는 것이 일반적입니다. 속성 호출을 통해서만 필드를 변경할 수 있도록 하기 위해 필드는 private로 표시되었습니다. 공용 및 개인 액세스 제한에 대한 자세한 내용은 액세스 한정자를 참조하세요.
자동 구현 속성은 간단한 속성 선언을 위해 간소화된 구문을 제공합니다. 자세한 내용은 자동으로 구현된 속성을 참조하세요.