참고 자료: MS Document
- C#이 생각보다 자료가 많이 없어서 그냥 공식문서 보고 정리하려고 한다.
일단은공식문서
상의 구조를 따라가려고 하는데 내용은 내 맘대로 써질 예정- 본질이 iOS 개발자라 많이 비교하면서 학습을 진행할 예정이다.
- @>--- 이런 기호와 함께 '기울임', '작게' 표시 되면 개인적인 생각이다.- 당연 이건 다른 언어를 했던 사람들이 C# 공부시 그나마 조금 편하라고 만들어 보는거지 아예 코드 짜는 사람이 처음이라면 이해 안될 수 있는다.
- 이해 안되는건 뒤에 나올 내용이 앞에 나와서 그러는거니까 첨보는 단어면 일단 넘어가면 뒤에 다시 나온다.
참조
형식이다.new 연산자
를 사용해 클래스의 인스턴스를 명시적으로 만들거나, 다른 곳에서 생성되었을 수 있는 호환되는 형식의 개체를 할당할 때까지
null을 포함한다.인스턴스를 만들 떄 해당 필드와 속성이 유용한 값으로 초기화하는 방법에는 여러 가지가 있다.
모든 .NET 형식에는 디폴트가 있는데 숫자 형식은 0
이고 모든 참조 형식은 null
이다.
기본값이 올바른 값이 아닌 경우 초기값을 설정 할 수 있다.
public class Container
{
private int _capacity = 10;
}
호출자가 초기 값을 설정하는 생성자를 정의해 초기 값을 제공하게 요구할 수 있다.
public class Container
{
private int _capacity;
public Container(int capacity) => _capacity = capacity;
}
=> : 이게 뭘까?
- 해당 연산자는
람다(Lamda)식
에서 사용되는람다 연산자
또는화살표 연산자
라고 불린다.람다 식
과본문 멤버
를 정의할 때 사용한다.1 . 람다식에서의 사용: 람다 연산자
람다식은익명 함수
를 표현하는 간결한 방법으로 메서드나 대라지를 정의하지 않고도 함수를 전달할 수 있다.
- 사용방법은
(입력 매개변수) => 식 또는 문장 블록
이런식으로 하며 사용 방법은2가지
가 있다.
- 이렇게 표기할때 입력 매개 변수가 없으면
() => 식 또는 문장 블록
으로 표현하면 된다.static void Main(string[] args) { var nums = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; List<int> search = nums.FindAll(x => x % 2 == 0); foreach (int n in search) Console.WriteLine(n); }
- 람다식은 뭔가 함수를 새로 지정해서 해당 동작을 하는 그런 로직을 짜기에는 코드가 길어져 바로바로 확인이 안되거나 진짜 간단 로직 + 1회성인걸 굳이 함수까지 만들 필요 없을때 쓰면 좋을것으로 보인다.
- 해당 코드 작성은 조금 더 익숙해져야 충분히 가능하겠지만 그런게 아니라면 초콤 문법 상으로 헷갈릴 여지가 있어보인다.
Func<int,int,int> check = (x,y) => { return x*y; };
@>--- 자주 이용할 것 같은 람다식 구현 방법
2 . Expression-bodied member (식 본문 멤버(?))
- 일단 예제 코드를 먼저 봐보자
public static int Add(int x, int y) => x + y;
- 뭔가 람다식과 비슷한 모습을 보이는것처럼 보이는데 엄밀히 말하면
완전 다른
개념이다.- 이 문법은 메서드, 속성, 생성자, 소멸자 등을 간결하게 표현하기 위해 사용된다.
- 해당 문법은 메서드나 속성의 본문을 간단한 식(expression)으로 대체하는 문법입니다.
- 메서드의
본문
이한 줄
로 간단히 표현될 때 =>를 사용해 이를 간결하게 나타낼 수 있습니다.@>--- 이게 뭔뜻이냐면 얘는 메서드라는거다.
그렇다는건, Main 함수 내에서 선언하고 바로 사용하고 메모리 날리고가 안된다는 소리다.정리
- 람다식 = 익명 함수 정의에 사용 + 주로 대리자(delegate)나 LINQ에서 함수형 프로그래밍을 지원하기 위해 활용
- Expression-bodied member = 간결하게 표현하는 방법으로 주로 코드의 가독성을 높이고 간단한 메서드를 축약할 때 사용
@>--- 약간 swift와 obj-C의 클로저나 블록과도 비슷한 느낌으로 보면 이해하기 쉬울것으로 보인다.
클래스 생성과 동시에 초기화 시키기
- 일단 예제 코드를 먼저 작성해보자
class Program { static void Main(string[] args) { TestClass tcl = new TestClass(); Console.WriteLine(tcl.ReadX()); } } class TestClass { private int x; public TestClass() => x = 3; public int ReadX() => x; }
- 여기서 눈여겨 볼 곳은 TestClas클래스의
TestClass 메서드
이다.
- 사용하는 방법은 매우 간단하다. 몇가지
조건
만 맞다면 애용하게 될 방법이다.
1] 클래스를 코드상에 입력할때는 그 값을 정하지 않는 즉, 동적인 변수가 필요로 할때 해당 변수의 값을 초기화 시킬떄
2] 해당 클래스가 처음 인스턴스로 할당될 때 해당 값이 초기화 되었으면 할때 사용하면 된다.
- 위의 조건들 외에도 여러 조건이 있겠지만 그걸 떠나 그냥 클래스 초기화 할때 쓴다 생각하믄 된다.
- 사용방법 또한 매우 쉬운데
public 클래스_이름(매개변수) = {초기화 구문}
이런식으로 클래스의이름과 똑같은
메서드를 만들어 뒤에 초기화 구문을 넣어주면 된다.- 예시 코드에서는 직접값을 넣어주고 있지만, 클래스 이름 뒤의 매개변수 넣는곳에 매개변수를 삽입해서 클래스 외부에서 변수의 값을 지정해줄 수 도 있다.
- 그리고
C# 12
에서 나온건데 아래처럼 직접 클래스 명에서 변수 때려서 하는것도 있는데 개인적으로는 전자의 방법을 더 애용할 것 같다.class TestClass(int inx) { private int x = inX; public int ReadX() => x; }
속성에서 required 한정자를 사용하고 호출자가 개체 이니셜라이저를 사용하여 속성의 초기 값을 설정하도록 허용할 수도 있습니다.
- 이 키워드를 사용해서 생성된 변수는! 무조건 초기화 작업을 해야 한다는것을 의미함 new 클래스() 하고 뒤에 {}
이렇게 해서!!
예시 코드는 다음과 같다.
class Program
{
static void Main(string[] args)
{
TestClass tcl = new TestClass() { y = 3 };
}
}
class TestClass
{
public required int y { get; set; }
}
상속
을 완전히 지원한다.sealed
로 정의디지 않은 다른 클래스에서 상속할 수 있다.파생
을 통해 수행된다.기본
,파생
을 나눠서 설명을 한다.기본
의 경우에는 가장 윗단 즉 트리의 루트 노드
같은 형식
을 이야기 한다.파생
의 경우에는 기본을 상속하는 모든 형식
들을 이야기 한다.파생
은 무조건 자식이 아닐 수도 있다. (이 파생을 상속하는 다른 파생이 있으면 부모이자 자식이 되는거니까)public class Sean: Person { ... }
클래스의 상속과 인터페이스
- swift와 다르게 C#에서의 클래스는
하나의
상속만 가능하기에 이를 조금이나마 따라하는 작업으로 인터페이스를 사용한다.- 여러 인터페이스를 구현함으로 다중 상속의
일부
기능을흉내
낼 수 있다.
중요한 키워드는일부
,흉내
이다.왜 일부 흉내일까?
상속과 인터페이스로 구현했을때의 코드 차이를 예시로 보여주겠다.
public class Animal { public void Eat() { Console.WriteLine("eating..."); } } public class Dog : Animal { public void NextAction() { Eat(); Console.WriteLine("next..."); } }
public interface Bird { void Fly(); } public interface Carnivore { void WantMeat(); } public class Eagle : Animal, Bird, Carnivore { public void Fly() { Console.WriteLine("flying..."); } public void WantMeat() { Console.WriteLine("Want Meat..."); } public void NextAction() { Fly(); Eat(); WantMeat(); Console.WriteLine("next..."); } }
상속은 애초에 부모의 모든것을 가져오기에
부모가 구현해둔
로직까지 다 가져올 수 있지만인터페이스의 경우에는 그렇다기 보다는 그냥
청사진
을 그려주는 역할밖에 못하기에 해당 로직은 선택한 클래스에서 구현을 해줘야 한다.그렇기에 의존성이나 관계도 또는 코드의 이해를 위하는 방법은 둘이 비슷할지 언정 정작 내부 디테일적으로 보게 되면 완벽하게 다른걸 알 수 있다.