struct와 class의 차이점




1) Type차이



구조체는 값 타입(value)

=> 스택메모리에 생성된다.


클래스는 참조 타입(reference)

=> 힙 메모리에 생성된다.


힙과 스택차이점


값타입과 참조타입 관련 예제


구조체는 함수안에서 1로 변경을 해도 외부 Main에서 값이 변경되지 않는다. 복사된 데이터는 원본 데이터가 아니기 때문에 복사된 값을 수정하면, 스택에 복사된 값을 변경하게 되는것이다. 

(복사본에 입력된 값들은 함수가 끝나면 사라짐)


 클래스는 참조타입으로 힙의 주소를 전달하기 때문에 값이 아닌 같은 주소가 참조된다. 

그래서 Main으로 출력했을 때, 값이 변경되지 않고 원본값을 출력한다.

(변경된 데이터들은 함수가 종료되어도 남아있음)




  

2) 클래스와 비슷하면서도 다른 구조체


a. 구조체는 생성자를 선언할 수 있으나 반드시 파라미터가 있어야한다.

b. 구조체는 상속이 불가능하다.

c. 구조체는 필드선언 시 const또는 static으로 선언한 경우에만 초기화가 가능하다.

d. new연산자를 사용하지 않고 인스턴스화 할 수 있다.




메모리절약은 클래스, 속도는 구조체


인스턴스한다면 가비지 컬렉션(속도)

구조체는 스택에 바로 할당되기 때문에 가바지컬렉터션이 발생 하지 않고, 클래스는 인스턴스를 생성할 때 마다 힙에 메모리 할당하기 때문에 값을 폐기하기 위해서는 가바지컬렉션이 필요하다. 


많은 양의 변수를 가지고 있는 구조체는 NO(메모리)

참조형식인 클래스는 값들을 가리키는 주소만 스택에 저장하지만 구조체는 가지고있는 변수들의 값들을 모두 스택에 저장되기 때문에 그 크기만큼 스택의 위치 역시 커지게 된다. 하지만 스택은 크기가 제한적이기 때문에 너무 많은 양을 가지게 되면 스택 오버플로우가 발생할 수 있는 위험이 있다. 


구조체는 언제 사용할까?


상황에 맞게 사용해야 하는 구조체

변수의 크기가 작거나, 수명이 짧고, 자주 할당되는 객체는 구조체로 만들어 주는게 좋다.

유니티에서는 position, color, quaternion, rotation, scale등이 구조체로 구현 되어있다.



학습참고

1) https://vaert.tistory.com/111

2) https://m.blog.naver.com/PostView.nhn?blogId=wow0815&logNo=90184259071&proxyReferer=https%3A%2F%2Fwww.google.com%2F

3) https://nowonbun.tistory.com/84 

4) https://ronniej.sfuh.tk/c-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B4%80%EB%A6%AC-%EA%B5%AC%EC%A1%B0%EC%B2%B4-vs-%ED%81%B4%EB%9E%98%EC%8A%A4/


struct

단순 데이터 컨테이터용으로 50개의 struct를 사용해봅시다.


struct는 메모리를 많이 사용합니다.


A->B->C 로 값을 전달하면, 총 150 개의 struct 가 생성되게 됩니다.


레퍼런스와 관련된 처리가 없으므로 더 빠를 수 있습니다.


구조체는 스택에 할당되고, 자신을 호출한 함수가 종료되면 즉시 사라집니다.

GC를 유발하지 않고 빠르게 동작합니다.


오히려 더 느려질 수도 있습니다.


단일 struct 오브젝트의 크기가 너무 커지거나, 너무 긴 리스트에 넣고 쓰면, 복사하는 시간이 길어집니다. 이때 class 형보다 처리 시간이 더 길어질 수 있습니다.


변수가 2~3개 뿐인 단순한 데이터 컨테이너라면 struct 를 사용하는게 빠릅니다.

일반적인 경우에는 class 를 쓰세요.

'프로그래밍언어 > C#' 카테고리의 다른 글

C#) 키워드 간단 정리  (0) 2019.09.24
C#) List / LinkedList (List.AddRange)  (0) 2019.06.05
C#) 쓰레드(Thread), 프로세스  (0) 2019.02.22
C#) 리플렉션 Reflection  (0) 2019.02.20
C#) Action과 Func (람다식)  (0) 2019.02.16

 

쓰레드(Thread)

 

쓰레드 란?

쓰레드는 어떠한 프로그램 내에서 특히 프로세스 내에서 실행되는 흐름의 단위를 말한다. 일반적으로 한 프로그램은 하나의 스레드를 가지고 있지만, 프로그램 환경에 따라 둘 이상의 쓰레드를 동시에 실행할 수 있다. 이러한 실행 방식을 멀티쓰레드라고 한다.

<위키 백과>

 

멀티프로세스와 멀티스레드는 양쪽 모두 여러 흐름이 동시에 진행되는 공통점이 있다. 하지만 멀티프로세스에서 각 프로세스는 독리적으로 실행되며 각각 별개의 메모리를 차지하고 있는 것과 다르게 멀티스레드는 프로세스 내의 메모리를 공유해 사용할 수 있다. 위키백과에서 나와 있듯이 쓰레드는 운영체제가 아닌 CPU시간을 할당하는 기본 단위이고, 프로세스는 하나 이상의 쓰레드로 구성 되는것이다.  또한 프로세스 간의 전환 속도보도다 스레드 간의 전환 속도가 빠르다. 

 

쓰레드의 상태

Unstarted

 쓰레드 객체를 생성한 후 Thread.Start() 메소드가 호출 되기 전의 상태

 Running

 쓰레드가 시작하여 동작 중인 상태.

 Unstarted 상태의 쓰레드를 Thread.Start() 메소드를 통해 이 상태

 Suspended

 쓰레드의 일시 중단 상태.

 쓰레드를 Thread.Suspend() 메소드를 통해 이 상태로 만들 수 있으며, Suspended 상태인 쓰레드는

 Thread.Resume() 메소드를 통해 다시 Running 상태

 WaitSleepJoin

 쓰레드가 블록(Block)된 상태

 쓰레드에 대해 Monitor.Enter(), Thread.Sleep(), Thread.Join() 메소드를 호출하면 이 상태

 Aborted

 쓰레드가 취소된 상태.

 Thread.Abort() 메소드를 호출하면 이 상태가 됩니다. Aborted 상태가 된 쓰레드는 다시 Stopped 상태로 전

 환되어 완전히 중지

 Stopped

 중지된 쓰레드의 상태

 Thread.Abort() 메소드를 호출하거나 쓰레드가 실행 중인 메소드가 종료되면 이 상태

 Background

 쓰레드가 백그라운드로 동작되고 있음, Foreground 쓰레드는 하나라도 살아 있는 한 프로세스

 가 죽지 않지만, Background는 여러개가 살아 있어도 프로세스가 죽고 사는 것에는 영향을 미치지 않는다.

 하지만 프로세스가 죽으면 Background 쓰레드는 모두 죽음. Thread.IsBackground 속성에 true 값을

 입력하면 쓰레드를 이 상태로 바꿀 수 있음.

 

쓰레드 라이프 싸이클

 

 

쓰레드 간단한 예제



 

 

학습 참고 :

 

1)  https://ko.wikipedia.org/wiki/%EC%8A%A4%EB%A0%88%EB%93%9C_(%EC%BB%B4%ED%93%A8%ED%8C%85)

2) https://nshj.tistory.com

3) https://codedragon.tistory.com/3526

4) https://dlgnlfus.tistory.com/295

5) https://acroama.tistory.com/m/43

 

리플렉션 Reflection


실행 중(런 타임)에 클래스나 객체의 타입 정보를 조사하는 기능, 리플렉션을 사용하여 형식의 인스턴스를 동적으로 만들거나, 형식을 기존 개체에 바인딩하거나, 기존 개체에서 형식을 가져오고 해당 메서드와 속성을 액세스 할 수 있다.(형식 이름, 포로퍼티, 메소드, 필드, 이벤트 목록을 모두 볼수 있고, 해당 메소드를 호출하거나 필드, 프로퍼티에 접근하는 것도 가능하 다는 것임)

타입 정보는 보통 컴파일 중에만 사용되며 컴파일러에 의해 기계어로 바뀌고 나면 사라지는 것이 일반적이다 하지만 C#은 컴파일된 결과 코드 뿐만 아니라 타입에 대한 메타 데이터를 실행 파일에 같이 기록해 놓기 떄문에 실행중에도 정보를 조사할 수 있다.


접근방법

지정된 이름으로 접근

1) Type t = Type.GetType("Test");


클래스 타입으로 접근

2) Type t = tyoeof("Test");


객체로 접근

3) Type t = Test.GetType()


프로그램의 metadata에 접근할 수 있도록 해주는 이 클래스는 System.Refelection namespace에 정의 해 주어야한다.

해당 메서드와 멤버변수들을 불러 올수 있다.







학습 참고

1) http://www.csharpstudy.com/Practical/Prac-reflection.aspx

2) https://hsj0511.tistory.com/350

3) https://hongjinhyeon.tistory.com/86


Action과 Func (람다식)


Action

Action은 파라미터가를 받아 들이는데, 리턴 값이 없는 함수에 사용되는 Delegate이다.


Action은 쓰려면 네임스페이스에 선언해줘야한다.

using System;

무명메델리게이트와 다른 Action 델리게이트

delegate void MyDelegate<T1, T2>(T1 a, T2 b); 와 다르게 네임스페이스에 선언한 System에 Action은 유니티시스템에 이미 정의되어있다.



Func 


Func는 Action과 비슷한데, 리턴값이 있을 경우 사용한다.

3번째 는 반환값 타입을 입력해줘야한다.


실제사용 코드 

테이블종류를 넣고 데이터를 리스트에 추가하는 코드이다, 여기서도 Action<bool>을 사용하였다. 



학습참고 : https://www.youtube.com/watch?v=7H3MHXfFkhI&index=19&list=PLUZ5gNInsv_O7XRpaNQIC9D5uhMZmTYAf

http://www.csharpstudy.com/Tip/Tip-Func.aspx



암시적 변환


C#은 컴파일 타임에서 정적으로 데이터 형이 지정된다. 변수의 형을 변환 하지 않으면 다시 선언하거나 다른 형태의 값에 넣는 것이 당연히 불가능하다,예외가 있는데 바로 암시적 변환 될 경우다.


형식이 안전하고 데이터가 손실되지 않으므로 특수 구문이 필요하지 않는다. 


1) 파생클래스 -> 기본클래스로 변환



2) 동일 데이터형의 큰타입으로 변환






명시적 변환(캐스트)


명시적 변환은 캐스트가 필요하다. 변환 시 정보가 손실 될 수도 있고, 암시적으로 변환된 작은 타입에서 큰타입으로 변환되는데 값의 손실이 없었지만 반대(큰타입->작은타입)는 값 손실이 있다.


그냥 변환하는것이 불가하고 캐스팅 키워드를 이용해야 한다.

앞에 '( 타입 )' 써준다.


1) 기본클래스 -> 파생클래스


2) (같은 타입)작은자료형 -> 큰자료형




학습참고 : https://guslabview.tistory.com/68

https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/types/casting-and-type-conversions

C#) 네임스페이스



가끔 "네임스페이스에 형식또는 네임스페이스 이름이 없습니다."라는 문구를 볼때가 있다.

네임스페이스를 알아보기 전에 작업 하다가 생긴 오류를 살펴보자


Define클래스

인터페이스나 enum같은 경우는 Defie클래스를 만들어서 한 곳에 정의하였다.


인터페이스를 사용하려는 클래스

아까 정의한 인터페이스를 사용하려는데? 

오류가 났다. 바로 'Global_Define' namespace를 선언해 주지 않았기 때문이다.


예시

콘솔창에서 텍스트를 출력하는 Console이 오류가 났다. 

이유는 System이라는 namespace가 없기 때문이다. 


Console클래스 정의로 이동해봤다.

Console이라는 클래스에는 WirteLine( )이라는 메서드가 있었다. 


Console이라는 클래스는 System 네임스페이스의 정의 되어있다.

System은 -> 네임스페이스

Console은 -> System의 정의되어있는 클래스

WirteLine은 -> Console클래스 에 정의된 메소드


네임스페이스 정의방법

첫 번째 

맨 윗단에 해당 using을 사용하여 C#파일에서 사용하고자 할때

두 번째

클래스명 앞에 네임스페이스 전부를 적는 경우 이 경우는 네임스페이스 안의 메소드, 

변수를 사용하려면 앞에 매번 적어줘야함 



네임스페이스는 즉 

소속이라는 정의하는 역할을 하는 것이다. 

네임스페이스를 귀찮게 나눠서 쓰는 이유.

이름이 같은 변수,메소드등등 이지만 실행되는 내용들은 다를 수 있기 떄문이다. 

A프로그램과 B프로그램이 있는데 같은 이름을 사용하지만 그 내용들이 조금 다르면?

프로젝트가 커지고 스크립트 수가 증가할수록 스크립트 클래스 이름이 충돌할 가능성이 커집니다. 이것은 게임의 다른 파트를 ​​따로 작업하고 궁극적으로 같은 프로젝트에 통합하는 경우에 적용됩니다. 예를 들어 한 명의 프로그래머가 메인 플레이어의 제어 코드를 만들고, 또 한사람이 적 캐릭터의 제어 코드를 작성했다고합니다. 둘 다 기본 스크립트 클래스를 Controller 라고 명명하고 프로젝트를 통합할 때 이름이 충돌합니다.

<유니티도큐>


유니티에 생성되는 namespace

유니티에서 스크립트를 생성하면 자동으로 추가 되는 것들이다. 클래스에서 Start나 Update메소드가 자동으로 생성되지만 있는 존재만으로도 비용이 들기 때문에 사용하지 않으면 삭제한다. namespace도 마찬가지이다. 사용하지 않으면 지워주자



학습참고 : 

1) https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/namespaces/

2) https://thinkpro.tistory.com/22

3) http://www.csharpstudy.com/csharp/CSharp-namespace.aspx


boxing/unboxing


박싱/언박싱?


내가 알고 있는 박싱/언박싱은 자료의 형변환이 일어날때

값 형식을 참조형식으로 박싱

참조형식을 값형식으로 언박싱이다 라는정도인데 메모리영역에서 어떻게 일어나는지 알아보았다.


박싱

값 형식을 참조 형식으로 변환되는 것을 말한다. 

static void Main(string[] args)

{ int i = 93; object s = i; //박싱 }

int i 는 93이라는 값을 받고, object s는 i의 값을 받고있다.

값 형식인 정수형 자료 int를 object(참조형식)객체로 할당하게 되면 박싱이 일어나게 된다.


=> 스택에 있는 데이터가 힙으로 복사 된 것이다.


Stack에 있는 93이라는 정수형 자료가 Heap영역으로 복사되고, 이영역을 객체 변수 s가 가리키게 된다.



언 박싱

참조 형식을 값 형식으로 변환하는 것,

static void Main(string[] args) { int i = 93; object s = i; int j = (int)s; //언 박싱(명시적 변환) }

s를 int로 값 형식으로 변환한다. 

박싱된 객체인 s를 다시 값 형식으로 변환하면 언박싱이 일어난다.


=> 힙에 있는 데이터가 스택으로 복사된다.



언 박싱이 가능한 객체

값 형식을 박싱하여 생성된 객체이어야만 가능

static void Main(string[] args) { short i = 93; object s = i; int j = (int)s; //언 박싱 불가 }

short타입을 박싱한 객체를 int타입으로 언 박싱은 불가능

해당 타입보다 작은 범위로 변환 불가능



높은 비용의 박싱/언박싱

박싱과 언박싱은 많은 시간이 소모된다고 한다. 되도록 제네릭을 사용해서 박싱과 언박싱이 일어나지 않도록 구성하도록 하는게 좋다.


박싱의 과정 : 

1. 값 타입을 힙에 생성하기 위해 메모리를 힙 영역에 생성

2. 값을 힙 영역에 할당된 메모리로 복사

3. 참조할 변수에 할당된 메모리 주소를 할당


언박싱의 과정 :

1. 박싱값인지 확인

2. 박싱된 값이라면 값 타입 변수에 복사

3. 박싱한 메모리와 언박싱한 메모리 2개 존재 ( 가비지 발생 )



학습참고 : http://www.mkexdev.net/Article/Content.aspx?parentCategoryID=1&categoryID=5&ID=671

 https://grayt.tistory.com/87 [IT's me]

https://hongjinhyeon.tistory.com/90


ref 키워드 (참조자)


C++에서 참조자 & 있다면 C#에는 단순히 참조를 하기위한 ref키워드가 있다. 

값형식이든 참조 형식이든 둘다 스택에 있는 값이 복사된다.


값 형식 : 스택영역메모리에 값이 직접 들어가있어서 그것이 복사된것

참조 형식 : 스택영역메모리에 힙영역의 주소가 들어있어서 그 주소가 복사되면서 같은 객체를 가리 킴

ref키워드를 이용하면 스택영역 메모리의 주소를 사용하면서 Call by reference를 사용하게된다. 


예제코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        static void Main(string[] args)
        {
            int a = 100;
            int b = 200;
            swapvalue(ref a, ref b);
            Console.WriteLine("변수{0}에 들어있는 수는{1}입니다.""a", a);
            Console.WriteLine("변수{0}에 들어있는 수는{1}입니다.""b", b);
 
        }
        static void swapvalue(ref int a, ref int b)
        {
            int temp = a;
            a = b;
            b = temp;
        }


a값과 b값이 변경되었다.


out 키워드 (참조자)


out키워드도 Call by reference를 가능하게 하는 키워드이며 

'출력용 매개변수'라고도 하여 값을 읽을 수 없는 쓰기용이다.

ref와 다른 특징들이 있다.


1. 현재 메소드가 끝나기 전에 out키워드가 붙은 변수는 값을 할당 받아야한다.

1
2
3
4
5
6
7
        static void swapvalue(ref int a, ref int b, out int c)
        {
            int temp = a;
            a = b;
            b = temp;
  //c 변수는 값을 할당 받아야한다.
        }

cs


2. out 키워드가 쓰인 변수는 함수내에서 값을 읽을 수 없다.

1
2
3
4
5
6
7
8
        static void swapvalue(ref int a, ref int b, out int c)
        {
            int temp = c; //에러
            a = b;
            b = temp;
            c = a;
 
        }
cs


예제코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        static void Main(string[] args)
        {
            int a = 100;
            int b = 200;
            int swapA ; //값 초기화 의미 X
            int swapB;  //값 초기화 의미 X
            swapvalue(a,b, out swapA, out swapB);
            Console.WriteLine("변수{0}에 들어있는 수는{1}입니다.""a", swapA);
            Console.WriteLine("변수{0}에 들어있는 수는{1}입니다.""b", swapB);
 
        }
        static void swapvalue(int a,int b, out int swapA, out int swapB)
        {
            swapA = b;
            swapB = a;
        
        }
cs


ref와 기능이 같은데 out키워드를 쓰는 이유?

ref키워드를 이용해서 매개 변수를 넘기는 경우에는 메소드가 해당 매개변수에 결과를 저장하지 않더라도 컴파일러는 아무런 경고를 하지 않는다.

하지만 out 키워드는 매개변수를 넘길 때 메서드가 해당 매개변수에 결과를 저 정하지 않으면 컴파일러 에러를 주면서 강제적으로 제한을 준다.

 또 첫 번째처럼 초기화를 하지 않아도 되는 이유는 호출당할 때 값을 할당할 것을 보장하기때문이다. 프로그램이 실행됐을 때가 아닌 코드를 작성하는 중에 컴파일 과정 에러를 확인할 수 있다.



공부참조

https://grayt.tistory.com/90?category=683217

https://runtoyourdream.tistory.com/279

https://grayt.tistory.com/90?category=683217

'프로그래밍언어 > C#' 카테고리의 다른 글

C#) 네임스페이스 / 유니티 네임스페이스  (0) 2019.02.13
C#) 박싱/언박싱 (boxing/unboxing)  (0) 2019.02.10
C#) Lamda #2  (0) 2019.02.07
C#) Lamda 람다 식  (0) 2019.02.06
C#) Generics 제네릭 클래스  (0) 2019.02.04

람다 Lamda  #2





앞서 공부한 

델리게이트를 써서 sum값을 출력해봤다.

//결과 값 15


이번에는 Print함수를 작성하지 않고 

무명메소드로 sum을 출력해봤다.

 //결과 값 15


이번에는 

람다식으로 sum을 출력했다.

// 결과 값 15


마지막으로

형식 매개변수를 이용해서 람다 식을 사용해 봤다.

// 결과 값 15 (유니티 디버그로 출력)

'프로그래밍언어 > C#' 카테고리의 다른 글

C#) 박싱/언박싱 (boxing/unboxing)  (0) 2019.02.10
C#) ref 키워드 (참조자) , out 키워드  (1) 2019.02.09
C#) Lamda 람다 식  (0) 2019.02.06
C#) Generics 제네릭 클래스  (0) 2019.02.04
C#) 비트연산자  (0) 2019.01.30

 Lamda 람다 식




람다 식은 대리자또는 식트리 형식을 만드는 데 사용할 수 있는 익명 함수이다.

람다 식을 사용하여 인수로 전달되거나 함수 호출값으로 반환되는 로컬 함수를 쓸 수 있다.


작성법

' => ' 왼쪽에 입력 매개 변수를 지정(있는 경우) 다른 쪽에 식이나 문 블록을 넣는다.


delegate int del(int i); static void Main(string[] args) { del myDelegate = x => x * x; int j = myDelegate(5); //j = 25 }




람다 식

무명 메소드를 단순한 계산식으로 표현 한 것이다.

메소드는 매개변수, 내부 식, 반환 값으로 구성 되어 있는데 이들을 가지고 메소드를 계산 식으로 표현할 수 있다.(=람다 식)



먼저 무명 메소드를 보면

매개변수 타입, 내부의 { } 내부 식, 반환 값을 입력 해주어야 한다.


무명메소드를 람다 식으로

 매개변수 타입, { }안 내부 식,내부 반환 값이 생략이 가능하다.




https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions

'프로그래밍언어 > C#' 카테고리의 다른 글

C#) ref 키워드 (참조자) , out 키워드  (1) 2019.02.09
C#) Lamda #2  (0) 2019.02.07
C#) Generics 제네릭 클래스  (0) 2019.02.04
C#) 비트연산자  (0) 2019.01.30
C#) abstract, virtual, override  (0) 2019.01.26


Generics 



일반적으로 클래스를 생성할 경우 각 데이터마다 타입을 지정해준다. 다른 데이터형을 사용하게 될 경우가 있는데, 강제 형변환은 좋지않다고 한다. 그래서~ 제네릭을 사용한다.


제네릭은 박싱/언박싱(형변환)이 일어나지 않도록 타입을 미리 지정하는 방식이다.

클래스,인터페이스, 메서드등에서도 구현 가능하다.


참조 타입 --> 힙 (Heap)

값 타입    --> 스택(Stack)

두 메모리 영역을 왔다갔다는 좋지않음


많이 사용했던 컬렉션들에서 이미 제네릭을 사용하고 있었다.


<출처 :  https://m.blog.naver.com/rocabilly/140133375098 >



Generics에서는 int, float, double같은 데이터 요소 타입을 확정하지 않고 이 데이터 타입 자체를 파라미터로 받아들이도록 클래스를 정의한다. 


형태

class 클래명 <T>

{

T 변수명;

}


public 메소드명 (T 변수명)

{

T 내부 변수명;

}

}


테스트 예제 코드

<결과>

이렇게 다른타입도 제네릭을 통해 원하는 결과를 도출 할 수 있다.




Generics 제약 Where


타입 파라미터가 값형식인지 참조 타입인지, 사용자가 정의한 베이스 클래스로부터 파생된 타입인지, 

어떤 인터페이스를 구현한 타입인지 등등을 지정 할 수 있다. 

제약을 걸어 사용자가 원하지 않는 형식의 매개변수를 넘기는 상황을 방지 할 수 있다.


형태

class 클래스명<T> where T : 제약형식

class 메소드명<T> where T : 제약형식

value(값) 타입

class MyClass<T> where T : struc


Reference(참조) 타입

class MyClass<T> where T  : class


T가 파생 클래스 일때

class MyClass <T> where T : MyBase


인터페이스

class MyClass <T> where T : Myinterface

등등..


2개 이상 제약이 가능함

class 클래스명<T,V> where T : 제약형식1, 제약형식2 where V : 제약형식


where <NAME> : <TYPE> 조건에 대한 제약사항

1) 구조체 및 정적 클래스는 사용할 수 없다.

2) 특수형식(object, Array, Delegate등)은 사용 불가

3) class와 struct조건은 같이 사용 불가




학습한 자료 사이트

http://www.csharpstudy.com/

https://m.blog.naver.com/rocabilly/140133303502

https://slaner.tistory.com/126

감사합니다.

'프로그래밍언어 > C#' 카테고리의 다른 글

C#) Lamda #2  (0) 2019.02.07
C#) Lamda 람다 식  (0) 2019.02.06
C#) 비트연산자  (0) 2019.01.30
C#) abstract, virtual, override  (0) 2019.01.26
C#) Delegate 콜백메서드,Delegate 체인 #3  (0) 2019.01.25

비트연산자



비트 단위로 논리 연산하고 비트 이동 연산을 수행하는 연산자이다.

실행속도와 표현의 편리성때문에 많이 사용된다고 한다.


& 비트단위 AND

| 비트단위 OR

^ 비트단위 XOR

<< 왼쪽으로 1비트 이동

>> 오른쪽으로 1비트 이동


<결과>




'프로그래밍언어 > C#' 카테고리의 다른 글

C#) Lamda 람다 식  (0) 2019.02.06
C#) Generics 제네릭 클래스  (0) 2019.02.04
C#) abstract, virtual, override  (0) 2019.01.26
C#) Delegate 콜백메서드,Delegate 체인 #3  (0) 2019.01.25
C#) 델리게이트 #2  (0) 2019.01.24

abstract (추상)


먼저 간단한 예제를 테스트해봤다.

1) 메서드에 abstract을 사용하려면 해당 클래스도 abstract로 선언되어야 한다.

2) abstract 키워드로 표시한 속성이나 메서드는 본문을 정의할 수 없고, 

파생된 자식클래스에서 이 메서드를 정의 할 수 있다.(반드시 정의 해야함)

3) 접근 한정자 private은 사용이 불가하다.

4) 새로운 개체 생성이 불가능하다. (파생 클래스로 생성가능)


.


Virtual (가상)

Virtual도 간단한 예제를 테스트 해봤다.

1) 메서드에 virtual 키워드를 붙여야한다.

2) 접근 한정자 private은 사용이 불가하다

3) abstract과 다르게 본문을 정의 할 수 있다. (괄호만 치고 비워 놓아도 됨)

4) 파생클래스에 base. 키워드를 쓰면 부모 클래스에있는 메소드에 있는 내용 실행할 수 있음

(Parents클래스의 test에 접근한다는 것임) 

<실행결과>


override

override키워드는 위에서 사용한 것 들을 보면 부모클래스에서 선언,정의한 내용을 상속을 받은 자식클래스에서 매서드를 재 정의 할때 사용 한다는 것을 알 수 있다. opp지향 언어의 다형성을 잘 보 여 주는 키워드이다.





'프로그래밍언어 > C#' 카테고리의 다른 글

C#) Generics 제네릭 클래스  (0) 2019.02.04
C#) 비트연산자  (0) 2019.01.30
C#) Delegate 콜백메서드,Delegate 체인 #3  (0) 2019.01.25
C#) 델리게이트 #2  (0) 2019.01.24
C#) 델리게이트(delegate) #1  (0) 2019.01.23

Delegate 콜백 메서드


콜백이란?_

A라는 메서드를 호출할 때, B라는 메서드를 매개변수로 넘겨주고 A메서드에서 B메서드를 호출하게 되는것이다.


Delegate 체인

델리게이트는 하나의 메소드만 참조하는 것이 아닌 여러개 메서드를 참조 할 수 있다.

추가 연산(+=)을 통해 메서드를 추가 할 수 있다. 

-=을 통해 빼기도 가능하다.



델리게이트는 해당 클래스 내부 뿐만 아니라 다른 클래스에서도 이 델리게이트를 호출 할 수 있는 장점이자 단점인 위험이 존재한다. 추가 연산(+=)이 아닌, 할당 연산(=)을 하게 되면 기록된 메서드를 모두 지워지니 조심해야한다.



'프로그래밍언어 > C#' 카테고리의 다른 글

C#) 비트연산자  (0) 2019.01.30
C#) abstract, virtual, override  (0) 2019.01.26
C#) 델리게이트 #2  (0) 2019.01.24
C#) 델리게이트(delegate) #1  (0) 2019.01.23
c#) 스태틱 Static 변수,메서드,클래스  (4) 2019.01.16

델리게이트 #2


Delegate를 메서드 파라미터로 전달

델리게이트는 메서드 타입(동일한 리턴타입&파라미터)이어야 사용할 수 있다.




MyDelegate 델리게이트는 리턴타입과 파라미터가 string으로 선언 되어 있고,

델리게이트로 사용 할 메서드들도 타입들도 string으로 정의 되어있다.

27번줄 : del = new MyDelegate(StringtestTwo); 을 줄여서 쓸수 있다.

<출력 결과>



 참고 : http://www.csharpstudy.com/CSharp/CSharp-delegate.aspx

델리게이트(delegate) #1



delegate 뜻은 대리인,(집단의 의사를 대표하는) 대표(자)라는 뜻이 있다 무엇인가를'대신'해주는 느낌이다.


델리게이트는 메서드를 다른 메서드로 전달할 수 있도록 하기 위해 만들어 졌다.


정의

delegate string MyDelegate(string s);

델리게이트 선언의 중요점은 입력 파라미터와 리턴 타입이다.

사용하려는 메서드는 입력 파라미터타입및 갯수, 리턴타입이 같아야 한다.


객체 생성

MyDelegate del = new MyDelegate(Stringtest);

클래스 객체를 생성하는 것과 비슷한 방식으로 new를 통해 생성한다. 괄호 안에는 사용할 메서드명을 넣어 준다.


델리게이트 전달

del = new new MyDelegate(Stringtest);

Testdel(del);


void Testdel(MyDelegate m)

{

s1s2 = m("gogo");

}

델리게이트 객체를 메서드 호출 파라미터에 넣으면 된다.



 

참조 : http://www.csharpstudy.com/CSharp/CSharp-delegate-concept.aspx

스태틱Static 변수


스태틱 변수는 객체를 선언만 해도 메모리가 할당되며 일반적인 변수들이 객체가 새로 생성될 때 메모리가 초기화 되는 것과 다르게 해당 객체를 계속 반복적으로 생성해도 메모리가 유지 된다는 특징이 있다. 

테스트를 해봤다

        public class Myclass

        { 

        private static int stNum= 0;

        private int num = 0;


        public Myclass()

        {

                stNum++;

                num++;

        }

     

        public void Showtest()

        {

            Console.WriteLine("stNum: {0},  num : {1}", stNum, num);

        }


    }

        static void Main(string[] args)

        {

            for (int i = 0; i < 5; i++)

            {

                Myclass test = new Myclass();

                test.Showtest();

            }

        }

    }


일반 변수인 num의 값은 변하지 않지만 Static으로 선언한 stNum은 메모리를 초기화 하지 않고 계속 더해 지고 있다. 

=> static 필드는 프로그램 실행 후 해당 클래스가 처음으로 사용될 때 한번 초기화되어

 계속 동일한 메모리를 사용하게 된다. 






스태틱Static 메소드



Static메소드는 객체가 메모리를 할당 받기 전에 호출이 되기 때문에 객체 생성 후 메모리 할당을 받는 일반 변수에 접근이 불가능하다. 인스턴스 메소드와 다르게 클래스로 객체를 따로 생성하지 않고 [클래스명.메서드명]이런식으로 호출하게 된다.

호출 시 일반 인스턴스 메서드와 달리 클래스로 부터 객체를 생성하지 않고 직접 호출한다. 



일반 인스턴스 메서드는 클래스로부터 객체를 생성하고 메서드를 호출해야하지만

static메서드는 [클래스명.메서드명]으로 메서드를 호출한다.


static메소드 내부에서 객체 멤버를 호출 할 수없다.

인스턴스 메서드는 스태틱메서드 멤버를 참조가 가능하지만 스태틱메서드는 다른 멤버 참조가 불가능하다.






스태틱Static 클래스



Static 클래스는 모든 클래스 멤버가 static 멤버로 되어 있으며, 클래스명 앞에 static이 붙는다.

다른 일반 클래스와 다르게 static생성자를 갖는다. 이 생성자는 보통 static필드를 초기화 할 때 사용한다.


테스트를 해보았다.



static 멤버 호출


객체 생성 불가

static는 인스턴스화 하지 않는 클래스이기 때문에 객체생성이 불가능하다.


 

스태틱객체는 프로그램이 종료되기 전까지 메모리를 해제하지 않고 객체를 생성하지 않고도 멤버에 접근이 가능하다는 장점 (특징)을 잘 활용해야 할 것같다. 하지만 단점으로 여러군데서 스태틱 멤버를 동시에 참조하게 될 경우와 객체 지향에 벗어난 개념이 되어 안좋다는 시선도 있다고 한다. 다른 장단점을 알아 볼 필요가 있겠다.



 참조 : http://www.csharpstudy.com/csharp/CSharp-static.aspx 사이트

http://ronniej.sfuh.tk/ , http://mygumi.tistory.com/253 ,http://blog.acronym.co.kr/347 블로그 





'프로그래밍언어 > C#' 카테고리의 다른 글

C#) 델리게이트 #2  (0) 2019.01.24
C#) 델리게이트(delegate) #1  (0) 2019.01.23
C#) 스택(Stack), 힙(Heap) 메모리구조  (0) 2019.01.15
C#)기본 개념 interface 인터페이스  (0) 2018.12.20
C#) continue , break 키워드  (0) 2018.11.14

스택(Stack), 힙(Heap) 메모리구조


우리가 어떤 동작을 할때(프로그램을 키거나) 운영체제는 그동작을 할 수 있게 메모리공간을 할당해준다.

그 할당해주는 메모리구조중 스택과 힙에 대해서 알아보자


스택 Stack 

프로그램은 함수의 호출로써 작동되는데 함수는 다른 함수를 호출하고 그 함수는 또 다른 함수를 호출하게된다. 함수들은 자신을 호출한 함수에게 결과를 반환한다.  함수 호출을 스택구조로 메모리에 차곡차곡  쌓고 처리가 끝나면 메모리에서 해제된다.

스택 메모리는 영역은 값 형식이다.

int a = 100;

int b = a;

b = 200;

a = 100;

a를 100으로 초기화하고 b는 a값을 넣어준다.

그리고 다시 b에는 200을 넣어주고 a는 100을 넣어준다.

결국은 a와 b는 마지막에 넣은100,200이 값이 되는것을 알 수있다.

스택메모리는 변수가 할당되었던 위치에 값만 변경되는것이다.

그리고 ,스택은 함수 호출 시 생성되는 지역 변수와 매개 변수가 저장되는 영역이며 함수 호출이 완료되면 해제한다.


힙 Heap

스택과 다르게 관리가 가능한(=사용자가 직접) 데이터 외에 다른 형태의 데이터를 관리하기 위한 빈 공간이라 생각하자

이 빈 공간은 동적생성된 변수를 관리 하기 위한 공간이다. 

힙 메모리 영역은 참조 형식이다.

Program p1 = new Program();

p1.value =200;

Program p2 = p1;

p2.value  = 100;

p를 동적 생성하고 값을 100을 넣어준다.

그리고 p2에 p1객체를 넣는다. 이 과정은 Stack에서의 복사가 이루어 진것이다.

p1이 참조하고있는 주소가 1000이라고 하면 p2 주소도 1000을 참조하게 된 것이다.

당연히 주소1000은 200을 참조하고 있으니 p2도 200을 참조하게 된다.

스택메모리에는 주소1000이 저장되고 힙메모리에는 값 200을 갖게된다.

네 번째줄  코드에서는 다시 100을 넣는다. 

당연히 같은 주소를 갖고있으니 p1,p2는 둘다 100을 값을 갖게 된다.

추가적인 특징으로 스택에는 메모리가 해제되는 시점이 있지만 힙에는 딱히 정해진 시점이 없다.

가비지콜렉터가 알아서 할당을 해제하기 때문이다. 

new로 동적 생성한 객체는 메모리는 힙에 만들어 지는 것과 동시에 가비지 콜렉터가 관리 되어 크게 신경쓸 필요는 없지만

가비지 콜렉터가 있으면 성능상으로 좋지 않다고 한다.


ref를 이용한 참조타입과 값타입 차이




인터페이스 interface


 클래스를 만들 때 사용하는 규약?



기본구조

interface [인터페이스 이름]

{

}



생성위치

인터페이스는 클래스와 동급의 카테고리이다. 그렇기 때문에 클래스를 생성하는 위치라면 어디든지 만들 수 있다.



예제를 보면서 이해하자



1) 인터페이스 생성

interface IBasic

{

int TestInstanceMethod( );

int TestProperty{  get; set ;}

}

메서드에 내부 구현을 입력할 수 없다.

속성에도 마찬가지로 내부 구현을 입력할 수 없다.


2) 인터페이스 상속

class TestClass : IBasic

{


}

static void Main(string[] args)

{

}


3) 인터페이스 구현

'Ctrl' + '.' 누르면 자동완성 

class TestClass : IBasic

{

public int TestInstanceMethod( )

{

throw new NotImplementedException( );

}

public int TestProperty

{

get

{

throw new NotImplementedException( );

}

set

{

throw new NotImplementedException( );

}

}

}

클래스에서 이후에 구현해준다.



4) 인터페이스 다중 상속

class Program

{


class Parent{ }

class Child : Parent, IDisposable, IComparable

{

public void Dispose( )

{

throw new NotImplementedException( );

}


public int CompareTo(object obj)

{

throw new NotImplementedException( );

}

}

//한 개의 클래스와 두 개의 인터페이스를 상속받는다.


이렇게 상속되면 다음과 같이 세종류로 자료형 변환이 가능해진다.

Child child = new Child( );

Parent ChildAsParent = new Child( );

IDisposable childAsDisposable = new Child( );

IComparable childAsComparable = new Child( );






break 키워드


조건문 또는 반복문을 벗어날 때에 사용하는 키워드입니다.


ex)


while (true)

{

Console.writeLine("무한반복문");

}


위 예같은 경우 계속 while문 안에있는 문장을 반복해서 출력하겠죠??


ex)

while (true)

{

Console.WriteLine("숫자를 입력해주세요(홀수를 입력하면 종료):");

int input = int.Parse(Console.ReadLine());


if (input % 2 == 1)

{

break;

}

}


이 예제는 어때요??

짝수를 입력하면 계속 실행하고

홀수를 입력하면 if문을 통해 break키워드가 실행되면서 바로 종료가 됩니다.




continue 키워드


반복문 내부에서 현재 반복을 멈추고 다음 반복을 진행하는 키워드입니다.


ex)

for(int i=1; i<=10; i++)

{

if(i%2==0)

{

continue; //짝수이면 다음 반복문으로 넘어갑니다. 아래코드 실행X

}

Console.WriteLine(i);

}


break문과 continue문을 활용하여 반복,조건문을 잘 활용 하시면 되겠습니다~

하지만 너무많은 사용은 코드의 가독성과 유지보수가 좋지 않기 때문에

남용은 좋지 않다고 하네요~





+ Recent posts