노력과 삽질 퇴적물

C#: 문법 스캔 (1) 본문

프로그래밍note/언어. C# 계열

C#: 문법 스캔 (1)

MTG 2021. 3. 1. 18:52
목차
(1)
 기본 문법
(2)
 이벤트, 비동기





 

0. 필요한 파일

 

파일명
 예시경로
 VS 2019 [#다운로드]
> 16.3 이상
 (기본경로)
 .NET Core 3.0 [#다운로드]  (기본경로)

* 해당 포스트는 C# 8.0기반이며, VS 업데이트는 16.8.6입니다.
* 해당 포스트는 JAVA/파이썬 같은 다른 프로그래밍 언어를 알고 있는걸 전제로 생략되는 부분이 있습니다.





1. 문법

 

1) 상수류
> 상수 선언시 static불가[#MSDN]
1
2
const int LIMIT_I = 100;//JAVA에서는 final
readonly int m_LIMIT;    //멤버변수에서 선언, 초기화는 클래스 생성자에
cs



2) 배열
> C#에서는 참조 타입

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//1차원 배열
long[] potions = new long[3];//고정된 크기로 선언.
string[] itemNames = {"체력 회복""스태미나 회복""경험치 물약"};
 
 
//2차원 배열
long[,] eventScores = {{1024512},{100-1}};//선언부터 초기화까지 완료.
 
long[][] eventScoreArr = new long[2][];//가변&2차원 배열
eventScoreArr[0= new long[10];//공간 선언O. 초기화X.
                                //그러니 eventScoreArr[0][0]로 호출시 exception.
eventScoreArr[1= new long[2] {-1-1};//공간 선언O. 초기화O.
 
 
//3차원 배열
long[,,] positions;
cs


3) 문자열
> 정확히는 StringBuilder 클래스를 쓰는 버릇 들이기.
> Immutable 타입 String클래스 Vs. Mutable타입 StringBuilder클래스
[C#] string + string 과 StringBuilder.Append() 차이
C#에서 String과 Stringbuilder를 사용하는 경우
-> 문자열 조합시, String형은 참조타입이라 새로운 객체를 생성 + GC
-> 변경 가능한 StringBuilder는 문자열 붙일때 객체 새로 생성X



4) 연산자
> Null-coalescing operator
> nullable 참조 형식 [#MSDN]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
string fromMsg = null;
string receiveMsg = fromMsg ?? "(기본 메시지)";
/*
if(fromMsg == null)
{
    receiveMsg = "(기본 메시지)";
}
else
{
    //do-nothing.
*/
Console.WriteLine("receiveMsg = "+receiveMsg);
 
int? resultCode = null;//Nullable 적용.
int receiveCode = resultCode ?? -1;
/*
C# 2.0부터 Nullable<int>처리가 가능.
Integer var = null;와 비슷하게 입력값 처리//JAVA
*/
Console.WriteLine("receiveCode = "+receiveCode );
cs
 
 
5) 반복문
> 순차적인 반복문이면 foreach가 권장.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
string[] itemCodes = ...
... ... ...
 
for(int idx=0; idx<itemCodes.Length; idx++)
{
    //do-something.
}
 
 
foreach (tmpItem in itemCodes)
{//CASE. 정방향으로 순차적
    //do-something.
}
 
foreach (tmpItem in itemCodes.Reverse())
{//CASE. 역방향으로 순차적
    //do-something.
}
cs
 
 
6) 네임스페이스
> 네임스페이스내에 클래스 N개 정의 가능.
> 파일명=클래스명이던 JAVA과 비교시, 네임스페이스 지정은 자유로워
: A.cs에 사용한 네임스페이스를 B.cs에도 동일한 네임스페이스 사용가능.
> 네임스페이스내 정의내 정의된 클래스를 가져다쓰려면
using (네임스페이스 경로).클래스명
: (JAVA)  import (패키지 경로).(클래스명)
  (C#)     using  (네임스페이스 경로).(클래스명)
-> 나름 협업 친화적인 규칙?


7) 구조체&클래스
구조체=값 타입(스택) / 클래스=참조 타입(힙)
 C#에서 구조체는 상속불가+인터페이스 가능.
② 클래스 멤버
> 필드변수: 기존의 멤버 변수 그거. + 여기서도 접근제한자 적용.
> 프로퍼티: 클래스 멤버 변수에서 함수처럼 [이름(...)]의 괄호가 없지만,
그 변수내에 get/set 정의 가능.
 
 
8) 함수 파라미터
① Pass by Value
> 함수인자에 변수값을 복사해서 전달.
> 함수에 값을 입력한다고 해서 함수 호출 이후 함수에 넣었던 변수값 변경X
 
② Pass by Reference
> 함수 인자에 ref/out키워드를 덧붙여 사용.
1
2
3
4
5
6
7
8
9
10
11
private void Prefix(ref int argA, out int argB)
{
    ... ... ...
    //do-somethging.
}
 
... ... ...
int codeForRef = 100;
int codeForOut;//초기화 불필요.
Prefix(codeForRef, out codeForOut);
//함수 호출로 codeForRef와 codeForOut의 값 변경된거 확인 가능.
cs
 
③ Named 파라미터
> C# 4.0부터 지원.
> 기존에는 함수 인자 입력시, 정의된 순서대로 값을 입력했다면
함수를 사용할때 key-value처럼 인자를 입력.

④ Optional 파라미터
> C# 4.0부터 지원.
> 자바스크립트에도 있는 함수 인자 기본값 지정
1
2
3
4
5
6
7
8
9
10
private void doFunction(int argA, int argB, int argC=-1)
{
    ... ... ...
    //do-something.
}
 
 
//함수 호출시 입력한 인자가 달라보여도 동일 함수 호출.
doFunction(20212);
doFunction(2021228);
cs
 
⑤ params 키워드
> JAVA로 치면 '가변인수'(Varargs)?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
//Test.java
 
void sendMsg(String... msgs)
{//msgs: 가변 배열인 함수 인자
    ... ... ...
 
sendMsg("test1");
sendMsg("test2_1", "test2_2");
*/
 
private void SendMsg(params string[] msgs)
{
... ... ...
}
 
SendMsg("test1");
SendMsg("test2_1""test2_2");
cs
 
⑥ Partial 키워드
> 다른 코드 파일이여도 동일한 클래스를 작업이 가능케 하는 키워드
 
 
8) 전처리기 지시어
① 조건별 컴파일
1
2
3
4
5
6
7
#if ENV_DEBUG
     //do-something.
#elif ENV_QA
     //do-something.
#else
     //do-something.
#endif
cs
 
② region
1
2
3
4
5
6
7
8
9
10
11
12
/*
함수나 멤버들 그룸 상하에
//START. func.DoXxx
... .... ...
//END. func.DoXxx
수동으로 하던거에 아예 접단 지원하는 지시어.
*/
 
#region Public DoXxx        
public void DoActionA() { }
public void DoActionB() { }        
#endregion
cs
 
 
9) static
> 정적 속성/필드: 프로그램 실행후 소속된 클래스가 처음 사용될때 초기화+동일한 메모리 사용.
> 정적 함수: [클래스명.함수명(...)]으로 호출&사용. 인스턴스 객체(혹은 객체화된 클래스)에서 호출 불가.
> 정적 클래스: 생성자 X, 객체화 불가 (싱글톤이 아닌 Utility용 클래스에 쓰던거와 동일)
 
 
10) 제네릭
> 클래스명<T>
: HashMap<>선언해서 쓸때 다양한 타입 허용하는 그거. (용어도 동일)
 
 
11) 익명타입 변수
> C# 3.0부터 지원.
> 변수 자료형을 var로 쓰는건데, C#에서는 읽기전용이라 함.
 
 
12) 확장 매소드(확장 함수)
> C# 3.0부터 지원.
> 굳이 String/Integer 클래스를 상속받아 추가 기능을 넣을 필요없이,
[네임스페이스.정적_클래스.정적_함수]로 정의해서
필요한곳에서 접착해서 사용.
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
//    확장 매소드(or 확장 함수)가 정의된 CS파일.
namespace Com.Muteukgi.ExtensionMethods
{
    public static class ExtenedFunction
    {
        public static int DoActionType1Ext(this int arg1)
        {
            int result = -1;
            //do-something.
            return result;
        }
        public static int DoActionType2Ext(this int arg1, int arg2)
        {
            int result = -1;
            //do-something.
            return result;
        }
    }
}
 
//다른 CS파일에서
using Com.Muteukgi.ExtensionMethods;
 
... ... ...
    int test = 100;
    int tmp = -1;
    tmp = test.DoActionType1Ext();
    tmp = test.DoActionType2Ext(2021);
cs
 
 
 
 
 
2. 이벤트, 비동기
 
1) 이벤트 핸들러
1
2
3
4
5
6
7
8
9
10
11
    ... ... ...
    xxx.Click += new EventHandler( ActionHandler );//핸들러 등록
    ... ... ...
    ... ... ...
    xxx.Click -= new EventHandler( ActionHandler );//핸들러 해제.
}
 
private void ActionHandler (object sender, EventArgs e)
{
    //do-something.
}
cs
 
 
2) 델리게이트(delegate)
> 예시나 설명을 보면,
: 상위 기능 함수(?) 내부에서 입력값별로 if-else나눈 블록에서 호출되는 세부 기능을 하는 함수 호출하는걸 도와주는 격.
: 상위 함수의 함수 인자가 delegate로 선언된 변수이면 그 인자에는 함수명을 변수처럼 입력하고, 상위 함수 내에서는 delegate형 변수는 코드상 입력된 함수의 코드대로 작동.
//지명된 다른 매소드 이름에 맞게 매소드 연기.
> 함수를 참조하는 변수로 함수 포인터랑 비슷하다는 설명도 있음.
: 함수 포인터 비슷하다 하지만, 델리게이트 1개-함수1개 이상 가능.(델레게이트 체인)
: 델리게이트 호출시 체인이 걸린 함수들이 순차적?동시에 실행? //세부 동작 확인 필요.
> 인스턴스/정적 함수 모두 가능.
> 제네릭 타입도 허용.
> 실질적인 용도는 콜백 매소드라 함.
 
 
3) 무명 함수(혹은 익명 함수)
> 이벤트 핸들러등에서 반복 사용될게 없는 코드를 함수 선언해서 쓰지않고, 내부 동작 자체를 그대로 붙여넣음.
1
2
3
4
5
6
7
8
9
10
11
/*
EventHandler에 쓰이는 함수의 인자는 (object sender, EventArgs e)인데,
익명형은 경우에 따라 함수인자도 생략된 형태O
*/
xxx.Click += new EventHandler(delegate(object s, EventArgs a) { /* do-something. */ });
 
xxx.Click += (EventHandler) delegate(object s, EventArgs a) { /* do-something. */ };
 
xxx.Click += delegate(object s, EventArgs a) { /* do-something. */ };
 
xxx.Click += delegate { /* do-something. */ };
cs
 
 
4) 람다
1
2
3
4
5
//type1.
(argA, argB) => {    /* do-something */    };
 
//type2.
(int argA, string argB) => {    /* do-something */    };
cs
 
 
5) async&await
> C# 5.0부터 지원된 비동기 관련 기능.
: 비동기 함수에도 반환값 처리 가능(JAVA로 치면 Future로 스레드에서 반환값 받는거.)
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
32
33
34
35
36
37
/*
In JAVA
ExecutorService service = Executors.newSingleThreadExecutor();
Future<T> future = service.submit(task);
REF. https://deep-dive-dev.tistory.com/6
*/
    ... ... ...
    Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
    DoAction();
}
 
private async void DoAction()
{    
    Debug.WriteLine("DoAction(1) " + Thread.CurrentThread.ManagedThreadId);
    int tmp = -1;
 
    tmp = await DoAsync(10);                //async 키워드 있는 함수로 비동기 처리
    Debug.WriteLine("tmp: " + tmp );
 
    var testTask = Task.Run( ()=>DoFunc(10) );//async 키워드 없는 함수로 비동기 처리
    tmp = await testTask;
    Debug.WriteLine("tmp: " + tmp );
    Debug.WriteLine("DoAction(2) " + Thread.CurrentThread.ManagedThreadId);
}
 
private async Task<int> DoAsync(int arg)
{
    Debug.WriteLine("DoAsync, " + Thread.CurrentThread.ManagedThreadId);
    ... ... ...
    return result;
}
 
private int DoFunc(int arg)
{
    ... ... ...
    return result;
}
cs
 
 
 
 

기타. 참조자료

1) 한국어
.NET Core 3.0의 새로운 기능 | Microsoft Docs
[C#] 왜 partial class를 사용하는걸까요?