일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 구조체
- c언어
- 유니티
- 도커
- C언어 포인터
- C++
- vim
- C# delegate
- jupyter
- jupyter lab
- gitlab
- Unity
- dart 언어
- docker
- c#
- git
- github
- 플러터
- Python
- Flutter
- HTML
- 다트 언어
- c# 윈폼
- c# 추상 클래스
- Houdini
- 포인터
- Algorithm
- c# winform
- 깃
- Data Structure
- Today
- Total
목록Programming (313)
nomad-programmer
https://asciinema.org/ asciinema - Record and share your terminal sessions, the right way Copy & paste Any time you see a command you'd like to try in your own terminal just pause the player and copy-paste the content you want. It's just a text after all! asciinema.org 아스키네마로 녹화해서 아스키네마 서버에 올린 것을 svg 애니메이션 파일로 추출한다. 그래서 이것을 github 같은 곳에 올릴 때 추가하면 무한 반복 자동 재생 애니메이션으로 사용할 수 있다. https://github.com/..
인덱서(Indexer) 는 인덱스(Index) 를 이용해서 객체 내의 데이터에 접근하게 해주는 프로퍼티라고 생각하면 된다. 객체를 마치 배열처럼 사용할 수 있게 해준다. 인덱서를 선언하는 형식은 다음과 같다. class 클래스이름 { // 인덱스의 식별자가 꼭 index라는 이름일 필요는 없다. 한정자 인덱서형식 this[형식 index] { get { // index를 이용하여 내부 데이터 반환 } set { // index를 이용하여 내부 데이터 저장 } } } 인덱서는 프로퍼티처럼 식별자(변수 이름) 를 따로 가지지 않는다. 프로퍼티가 이름을 통해 객체 내의 데이터에 접근하게 해준다면, 인덱서는 인덱스를 통해 객체 내의 데이터에 접근하게 해준다. using System; using System.Co..
컬렉션이란, 같은 성격을 띄는 데이터의 모음을 담는 자료 구조를 말한다. 배열도 .NET Framework가 제공하는 다양한 컬렉션 자료 구조의 일부이다. .NET Framework의 여타 컬렉션들이 상속하게 되어 있는 ICollection 인터페이스를 상속함으로써 System.Array 클래스 자신이 컬렉션의 일원임을 증명하고 있다. public abstract class Array : ICloneable, IList, ICollection, IEnumerable .NET Framework는 배열 말고도 여러 컬렉션 클래스들을 제공한다. ArrayList (자료 구조에서의 Linked List, Python에서는 list) Queue (Python에서 Queue 모듈) Stack (Python에서 li..
2차원 배열이나 3차원 배열 같은 다차원 배열을 "배열을 요소로 갖는 배열" 이다. 허나 진정한 의미에서의 배열을 요소로 갖는 배열은 "가변 배열 (Jagged Array)" 이다. 가변 배열은 다양한 길이의 배열을 요소로 가지는 다차원 배열로 이용될 수 있다. 2차원 배열의 요소에 접근할 때 반드시 첨자 두 개를 사용해야 했다. 하나만 사용해서 1차원 배열에 접근한다거나 하는 일은 불가능하다. 아래의 예를 보자. int[,] arr2d = new int[2, 3] { {1, 2, 3}, {4, 5, 6} }; // 2차원 배열이면 첨자 2개가 필히 들어가야 한다. arr2d[1, 2]; // 2차원 배열이면 첨자가 1개 뿐이라면 에러 발생. 1차원 배열에 접근할 수 없다... arr2d[1]; 가변 배..
다차원 배열이란 차원이 둘 이상인 배열을 말한다. 2차원 배열도 다차원 배열에 해당한다. using System; namespace test { internal class Program { public static void Main(string[] args) { int[,,] arr3d = new int[4, 3, 2] { { {0, 1}, {2, 3}, {4, 5} }, { {6, 7}, {8, 9}, {10, 11} }, { {12, 13}, {14, 15}, {16, 17} }, { {18, 19}, {20, 21}, {22, 23} } }; for (int i = 0; i < arr3d.GetLength(0); i++) { for (int j = 0; j < arr3d.GetLength(1); j..
C#에서는 모든 것이 객체이다. 배열도 객체이며 당연히 기반이 되는 형식이 있다. .NET Framework의 CTS (Common Type System) 에서 배열은 System.Array 클래스에 대응된다. 따라서 System.Array의 특성과 메소드를 파악하면 배열의 특성과 메소드를 알게 되는 셈이다. Array 클래스의 주요 메소드와 프로퍼티 분류 이름 설명 정적 메소드 Sort() 배열을 정렬한다. BinarySearch() 이진 탐색을 수행한다. IndexOf() 배열에서 찾고자 하는 특정 데이터의 인덱스를 반환한다. TrueForAll() 배열의 모드 요소가 지정한 조건에 부합하는지의 여부를 반환한다. FindIndex() 배열에서 지정한 조건에 부합하는 첫 번째 요소의 인덱스를 반환한다...
추상 클래스는 클래스처럼 구현된 프로퍼티를 가질 수도 있는 한편, 인터페이스처럼 구현되지 않은 프로퍼티도 가질 수 있다. 추상 클래스에서는 이것을 "추상 프로퍼티 (Abstract Property)" 라고 한다. 추상 메소드가 그랬던 것처럼, 추상 프로퍼티 역시 인터페이스의 프로퍼티와 다를 것이 없다. 파생 클래스가 해당 프로퍼티를 구현하도록 강제하는 것일 뿐이다. 추상 프로퍼티는 인터페이스처럼 구현을 비워놓은 것만으로는 추상 프로퍼티를 만들 수 없다. 그리하면 C# 컴파일러가 자동 구현 프로퍼티로 간주하고 구현을 자동으로 채워 넣을 것이다. 그래서 추상 프로퍼티는 abstract 한정자를 이용하여 선언한다. abstract class 추상 클래스이름 { abstract 데이터형식 프로퍼티이름 { get..
인터페이스는 메소드뿐만 아니라 프로퍼티와 인덱서도 가질 수 있다. 프로퍼티나 인덱서를 가진 인터페이스를 상속하는 클래스가 반드시 해당 프로퍼티와 인덱서를 구현해야 하는 것은 물론이다. 당연한 이야기지만 인터페이스에 들어가는 프로퍼티는 구현을 갖지 않는다. 인터페이스의 프로퍼티 선언이 클라스의 자동 구현 프ㅗ퍼티 선언과 그 모습이 동일하다. 다음은 인터페이스의 프로퍼티 선언 형식이다. interface 인터페이스이름 { public 형식 프로퍼티1 { get; set; } public 형식 프로퍼티2 { get; set; } } 다음은 프로퍼티를 갖고 있는 인터페이스와 이를 상속하는 파생 클래스의 예이다. interface INameInfo { string Name { get; set; } } class ..
이름이 없는 형식, 즉 "무명 형식 (Anonymous Type)" 의 프로퍼티를 정의할 수 있다. 무명 형식은 형식의 선언과 동시에 인스턴스를 할당한다. 이 때문에 인스턴스를 만들고 다시는 사용하지 않을 때 요기하게 쓰인다. // 괄호 사이에 임의의 프로퍼티 이름을 적고 값을 할당하면 그대로 새 형식의 프로퍼티가 된다. var myInstance = new { Name = "test", Age = 17 }; Console.WriteLine( myInstance.Name, myInstance.Age ); 무명 형식에는 주의할 점이 있다. 그것은 무명 형식의 프로퍼티에 할당된 값은 변경 불가라는 점이다. 한마디로 한번 무명 형식의 인스턴스가 만들어지고 난 다음에는 읽기만 할 수 있다는 것이다. 이러한 특징..
프로퍼티를 이용한 초기화는 다음과 같다. 클래스이름 인스턴스 = new 클래스이름() { 프로퍼티1 = 값, 프로퍼티2 = 값, 프로퍼티3 = 값 } 객체를 생성할 때 목록에 객체의 모든 프로퍼티가 올 필요는 없다. 초기화하고 싶은 프로퍼티만 넣어서 초기화하면 된다. 매개 변수가 있는 생성자를 작성할 때와는 달리 어떤 필드를 생성자 안에서 초기화할지를 미리 고민할 필요가 없다. using System; namespace CSharpExample { class MainApp { class BirthdayInfo { public string Name { get; set; } public DateTime Birthday { get; set; } public int Age { get { return new Da..
프로퍼티는 데이터의 오염에 대해선 메소드처럼 안전하고, 데이터를 다룰 때는 필드처럼 간결하다. 하지만 많은 경우 중복된 코드를 작성하고 있다는 기분이 들게 된다. 다음 코드의 NameCard 클래스를 보면 Name과 PhoneNumber 프로퍼티는 단순히 name과 phoneNumber 필드를 읽고 쓰기만 하고 있다. 여기에는 아무 논리도 섞여 있지 않다. 이런 경우 C# 언어는 더 단순하게 만드는 "자동 구현 프로퍼티 (Auto-Implemented Property)" 를 C# 3.0 때 도입했다. public class NameCard { private string name; private string phoneNumber; public string Name { get { return name; } ..
* Python의 property, setter 데코레이션과 똑같다고 생각하면 된다. 객체 지향 언어라면 모름지기 "은닉성"을 표현할 수 있어야 한다. 객체의 데이터가 의도하지 않게 오염되는 것을 방지해야 하니까. C++나 Java에서는 private과 protected 접근 한정자를 이용해서 클래스 내의 필드를 외부에서 보이지 않게 감추고, 이 필드에 접근하는 메소드들을 public으로 따로 제공한다. C# 언어도 이 방법을 그대로 사용할 수 있지만, C# 언어는 이보다 더 우아한 장치를 제공한다. 그것이 바로 프로퍼티(Property)이다. 프로퍼티를 이용하는 이유? 은닉성과 편의성 예를 들어 다음과 같은 클래스가 있다고 해보자. 이 클래스는 int 형식 myField를 private로 갖고 있다. ..
추상 클래스는 인터페이스와 달리 "구현"을 가질 수 있다. 하지만 클래스와는 달리 인스턴스를 가질 수 없다. 한마디로 추상 클래스는 구현을 갖되 인스턴스는 만들지 못한다. abstract class 클래스이름 { // 클래스와 동일하게 구현 } 추상 클래스가 인터페이스와 클래스의 중간에 있다고 했지만 추상 클래스는 클래스에 더 가깝다. 추상 클래스의 접근성이 그 예이다. 클래스와 똑같다. 인터페이스에서는 모든 메소드가 public으로 선언되는 반면, 클래스는 한정자를 명시하지 않으면 모든 메소드가 private로 선언된다. 한편, 추상 클래스에는 인스턴스를 만들 수 없는 점 외에도 클래스와 다른 점이 또 하나 있다. 그것은 바로 "추상 메소드 (Abstract Method)" 를 가질 수 있다는 사실이다..
C#에서 클래스는 여러 클래스를 다중 상속할 수 없다. 이른바 "죽음의 다이아몬드" 라는 문제 때문이다. 죽음의 다이아몬드란, 조부모 클래스를 두 개의 파생 클래스가 상속하고, 이 두 개의 파생 클래스를 다시 하나의 자식 클래스가 상속하는 것을 말한다. 죽음의 다이아몬드 문제의 핵심은 "모호성" 이다. 컴파일은 MyVehicle이 어느 Ride() 메소드를 물려받도록 할까? Car의 Ride()? 아니면 Plane의 Ride()? 죽음의 다이아몬드 문제의 핵심은 모호성이다. 컴파일러 상태에 따라 Car의 Ride()가 물려받을 수도 혹은 Plane의 Ride()가 물려받을 수 있다. 클래스를 다중 상속하면 문제가 하나 더 발생한다. 바로 "업-캐스팅 (Up-Casting)" 문제이다. 다중 상속이 허용된..
인터페이스를 상속할 수 있는 것은 클래스뿐이 아니다. 구조체는 물론이고, 인터페이스도 인터페이스를 상속할 수 있다. 기존의 인터페이스에 새로운 기능을 추가한 인터페이스를 만들고 싶을 때 인터페이스를 상속하는 인터페이스를 만들면 된다. 기존에 존재하는 인터페이스에 새로운 기능을 추가해도 되지만 다음의 경우처럼 인터페이스를 수정할 수 없을 때에는 인터페이스를 상속하는 인터페이스를 이용해야 한다. 상속하려는 인터페이스가 소스 코드가 아닌 어셈블리로만 제공되는 경우 : .NET Framework SDK에서 제공하는 인터페이스들이 그 예이다. 어셈블리 안에 있기 때문에 인터페이스를 수정할 수 없다. 이인터페이스에 새로운 기능을 추가한 인터페이스를 만들고 싶으면 상속하는 수밖에 없다. 상속하려는 인터페이스의 소스 ..
인터페이스는 객체 지향 프로그래밍을 한층 더 강력하게 만들어주는 요소이다. 객체 지향 프로그래밍의 꽃이라고도 불리며 객체 지향 프로그래밍의 고수는 인터페이스를 잘 활용할 수 있어야 한다고 말하기도 한다. 인터페이스의 선언 인터페이스(Interface)는 다음과 같이 interface 키워드를 이용하여 선언한다. interface 인터페이스이름 { 반환형식 메소드이름1(매개 변수 목록); 반환형식 메소드이름2(매개 변수 목록); . . . } // 인터페이스 실제 정의 예 interface ILogger { void WriteLog( string log ); } 클래스를 선언하는 것과 비슷하다. 허나 메소드, 이벤트, 인덱서, 프로퍼티만을 가질 수 있다. 그런데 그나마도 구현부가 없다. 그리고 클래스는 접..
* Python의 튜플(Tuple)과 똑같다고 생각하면 된다. 튜플도 여러 필드를 담을 수 있는 구조체이다. 하지만 구조체와는 달리 튜플은 형식의 이름을 가지지 않는다. 그래서 튜플은 응용 프로그램 전체에서 사용할 형식을 선언할 때가 아닌, 임시적으로 사용할 복합 데이터 형식을 선언할 때 적합하다. 튜플은 구조체이므로 값 형식이다. 값 형식은 생성된 지역을 벗어나면 스택에서 소멸되기 대문에 프로그램에 장기적인 부담을 주지 않는다는 장점이 있다. // 컴파일러가 튜플의 모양을 보고 직접 형식을 결정하도록 var를 이용해 선언. // 튜플은 괄호 사이에 두 개 이상의 필드를 지정함으로써 만들어진다. var tuple = (123, 789): 위와 같이 이름을 지정하지 않은 튜플을 일컬어 "명명되지 않은 튜플..
C#의 복합 데이터 형식에는 클래스 말고도 구조체(Structure)라는 것이 있다. 구조체는 클래스하고 사촌지간쯤 된다. 필드와 메소드를 가질 수 있는 등 상당 부분 비슷하다. struct 구조체이름 { // 필드, ... // 메소드, ... } struct MyStruct { public int field1 public int field2 public void MyMethod() { } } 구조체에서 public을 많이 사용하는 이유? 문법적으로 클래스와 유사하기는 해도, 각자의 존재의 이유는 조금 다르다. 클래스는 실세계의 객체를 추상화하려는데 그 존재의 이유가 있지만, 구조체는 데이터를 담기 위한 자료 구조로 사용된다. 따라서 굳이 은닉성을 비롯한 객체 지향의 원칙을 구조체에 강하게 적용하지는 ..
확장 메소드(Extension Method)는 기존 클래스의 기능을 확장하는 기법이다. 부모 클래스를 물려받아 파생 클래스를 만든 뒤 여기에 필드나 메소드를 추가하는 상속과는 다르다. 확장 메소드는 이미 존재하는 클래스의 기능을 확장한다. 확장 메소드를 이용하면 string 클래스에 문자열을 뒤집는 기능을 넣을 수도 있고, int 형식에 제곱 연산 기능을 넣을 수도 있다. 확장 메소드를 선언하는 방법 메소드를 선언하되, static 한정자로 수식해야 한다. 그리고 이 메소드의 첫 번째 매개 변수는 반드시 this 키워드와 함께 확장하고자 하는 클래스(형식)의 인스턴스여야 한다. 그 뒤에 따라오는 매개 변수 목록이 실제로 확장 메소드를 호출할 때 입력되는 매개 변수이다. 메소드는 클래스 없이 선언될 수 없..
분할 클래스(Partial Class)란, 여러 번에 나눠서 구현하는 클래스를 말한다. 분할 크래스는 그 자체로 특별한 기능을 하는 것은 아니고, 클래스의 구현이 길어질 경우 여러 파일에 나눠서 구현할 수 있게 함으로써 소스 코드 관리의 편의를 제공하는 데 그 의미가 있다. using System; namespace CSharpExample { partial class MyClass { public void Method1() { Console.WriteLine("method1"); } public void Method2() { Console.WriteLine("method2"); } } // 클래스 이름이 등일해야 한다. partial class MyClass { public void Method3() ..