-
[C# / .NET] Java와 다른 문법카테고리 없음 2022. 4. 7. 22:04
Java와 다른 것 위주로 기술
로컬함수
로컬함수는 메소드 안에서 선언되고, 선언된 메소드 안에서만 사용되는 특별한 함수
클래스의 멤버가 아니기 때문에 메소드가 아니라 함수라고 부름
class SomeClass { public void SomeMethod() { int count = 0; SomeLocalFunction(1,2); //로컬 함수 호출 void SomeLocalFunction(int a, int b) //로컬 함수 선언 { //Do Some Work Console.WriteLine($"count : {++count}"); //로컬 함수는 자신이 속한 메소드의 지역 변수를 사용할 수 있음 } } }
선택적 인수
메소드의 기본변수는 기본값을 가질 수 있음
void MyMethod(int a, int b = 0) { Console.WriteLine("{0}, {1}", a, b); }
이와 같이 기본 값을 가진 매개변수는 메소드 호출시 해당 인수를 생략할 수 있음
MyMethod(3);
MyMethod(3, 4);
가변 개수의 인수
프로그래밍을 하다 보면 그저 인수의 '개수' 개수가 다르다는 이유만으로 똑같은 메소드를 여러 가지 버전으로 오버로딩하고 싶을 때가 많음
이런 경우를 위해 C#은 '가변 개수의 인수'라는 기능을 제공함
가변 개수의 인수란, 그 개수가 유연하게 변할 수 있는 인수를 뜻함
이것을 이용하면 다음과 같이 입력되는 모든 인수의 합을 구하는 Sum() 메소드를 오버로딩하지 않고도 구현할 수 있음
int total = 0; total = Sum(1); total = Sum(1,2); total = Sum(1,2,3,4); total = Sum(1,2,3,4,5,6); total = Sum(1,2,3,4,5,6,7,8);
가변 개수의 인수는 params 키워드와 배열을 이용해서 선언함
다음은 가변 개수의 인수를 이용해서 모든 합을 구해 반환하는 Sum() 메소드의 구현임
이렇게 구현한 메소드는 앞에서 본 코드에서처럼 인수의 개수를 달리해서 호출할 수 있음
int Sum( params int[] args ) { int sum = 0; for(int i=0; i<args.Length; i++){ sum += args[i]; } return sum; }
메소드의 결과를 참조로 반환하기
참조 반환값을 이용하면 메소드의 호출자로 하여금 반환받은 결과를 참조로 다룰 수 있도록 함
class SomeClass{ int SomeValue = 10; public ref int SomeMethod(){ return ref SomeValue; } } Main ..(){ //ref 사용 안 하는 예제 SomeClass obj = new SomeClass(); int result = obj.SomeMethod(); //ref 사용하는 예제 SomeClass obj = new SomeClass(); ref int result = ref obj.SomeMethod(); }
using System; namespace RfReturn { class Product{ private int price = 100; public ref int GetPrice(){ return ref price; } public void PrintPrice(){ Console.WirteLine($"Price : {price}"); } } class MainApp{ static void Main(String[] args){ Product carrot = new Product(); ref int ref_local_price = ref carrot.GetPrice(); int normal_local_price = carrot.GetPrice(); carrot.PrintPrice(); Console.WriteLine($"Ref Local Price : {ref_local_price}"); Console.WirteLine($"Normal Local Price : {normal_local_price}"); ref_local_price = 200; carrot.PrintPrice(); Console.WriteLine($"Ref Local Price : {ref_local_price}"); Console.WirteLine($"Normal Local Price : {normal_local_price}); } } } /* ========== 결과 ========== Price : 100 Ref Local Price : 100 Normal Local Price : 100 Price : 200 Ref Local Price : 200 Normal Local Price : 100 */
goto
goto? 점프문
goto 레이블;
레이블 :
//이어지는 코드
{ Console.WriteLine(" 1 "); goto JUMP; Console.WriteLine(" 2 "); Console.WriteLine(" 3 "); JUMP: Console.WriteLine(" 4 "); } /* ===== 결과 ===== 1 4 */
foreach
int[] arr = new int[]{0,1,2,3,4}; foreach(int a in arr) //java는 ? for(int a : arr){} { Console.WriteLIne(a); }
switch식
Swtich문이 아닌 switch식
//switch문 int score = Console.ReadLine(); string grade; switch(score) { case 90: grade = "A"; break; case 80: grade = "B"; break; case 70: grade = "C"; break; case 60: grade = "D"; break; default: grade = "F"; } //switch식 int score = Console.ReadLine(); string grade = score switch{ 90 => "A", 80 => "B", 70 => "C", 60 => "D", _ => "F" }; //switch식 - when 절을 활용 bool repeated = true; string grade = score switch{ 90 when repeted == true => "B+", 90 => "A", 80 => "B", 70 => "C", 60 => "D", _ => "F" }
상속
class Base { int public void BaseMethod() { Console.WriteLine("BaseMethod"); } } class Derived : Base { //Derived 클래스는 Base 클래스를 상속했으므로 BaseMethod()를 가짐 public void DerivedMethod() { base.BaseMethod(); //java super 같은 } }
class Base { protected String Name; public Base(string Name) { this.Name = Name; } } class Derived : Base { public DerivedMethod(string Name) : base(Name) //Base(string Name) 호출 { base.BaseMethod(); //java super 같은 } }
using System; namespace Inheritance { class Base { protected String Name; public Base(string Name) { this.Name = Name; Console.WriteLine($"{this.Name}.Base()"); } ~Base() { Console.WriteLine($"{this.Name}.~Base()"); } public void BaseMethod() { Console.WriteLine($"{Name}.BaseMethod()"); } } class Derived : Base { public Derived(string Name) : base(Name) { Console.WriteLine($"{this.Name}.Derived()"); } ~Derived() { Console.WriteLine($"{this.Name}.~Derived()"); } public void DerivedMethod() { Console.WriteLine($"{Name}.DerivedMethod()"); } } class MainApp { static void Main(string[] args) { Base a = new Base("a"); a.BaseMethod(); Console.WriteLine(); Derived b = new Derived("b"); b.BaseMethod(); b.DerivedMethod(); } } } /* ======== 결과 ======== a.Base() a.BaseMethod() b.Base() b.Derived() b.BaseMethod() b.DerivedMethod() */
상속 봉인도 가능
sealed class Base{ ... }
class Derived : Base { ... } => 컴파일 에러남
형식 변환을 위한 연산자 is, as
- is : 객체가 해당 형식에 해당하는지 검사하여 그 결과를 bool 값으로 반환함 (java의 instanceof 와 같아 보임)
Base bs = new Derived(); Derived dv; if(bs is Derived) { dv = (Derived)bs; }
- as : 형식 변환 연산자와 같은 역할을 함. 다만 형식 변환 연산자가 변환에 실패하는 경우 예외를 던지는 반면에 as 연산자는 객체 참조를 null로 만든다는 것이 다름.
Base bs2 = new Derived(); Derived dv2 = bs2 as Derived; if(dv2 != null) //bs2가 Derived 형식 변환에 실패했다면 null이 됨, 하지만 이코드에서는 안전하게 형식 변환이 이루어짐 { Console.WriteLine("complete"); }
오버라이딩(Overriding)
자식 클래스에서 부모 클래스의 메소드를 오버라이딩 하기 위해서는 부모 메소드에 virtual을 명시해주어야 하며,
자식 메소드에는 override를 명시해주어야 함
class Base{ public virtual void UtilMethod(){ Console.WriteLine("Base Util Method()"); } } class Derived{ public override void UtilMethod(){ Console.WriteLine("Derived Util Method()"); } }
const vs readonly
- 상수 : 변하지 않는 값
- 변수 : 자유롭게 변하는 값
- 읽기 전용 : 상수와 변수 사이 그 중간 어딘가
class D { private readonly int r; private const int i ; //컴파일 에러 발생 => 반드시 선언과 동시에 초기화를 해주어야 함 public D(int n){ r = n; //생성자 안에서만 초기화가 가능 } public Method(int n){ r = n; //컴파일 에러 } }
중첩 클래스
class A{ class B{ } }
중첩클래스를 쓰는 이유?
- 클래스 외부에 공개하고 싶지 않은 형식을 만들고자 할 때
- 현재 클래스의 일부분처럼 표현할 수 있는 클래스를 만들고자 할 때
프로퍼티
java에서는 class의 private 변수에 접근하기 위해 보통 아래와 같이 사용했었음
class MyClass{ private int myField; public int GetMyField() { return myField; } public void SetMyField(int num) { myField = num; } }
그런데 C#의 프로퍼티를 활용하면 아래와 같이 간단하게 표현 할 수 있고, '='을 통해 바로 변수 값을 설정할 수 있음
class 클래스 이름 { 데이터형식 필드이름; 접근한정자 데이터형식 프로퍼티이름 { get { return 필드이름; } set { 필드이름 = value; } } }
프로퍼티 선언 문법에서 get {...} set {...} 을 일컬어 접근자라고 함
value 키워드는 선언한 적은 없지만, c# 컴파일러는 set 접근자의 암묵적 매개변수로 간주함
class MyClass { private int myField; public int MyField { get { return myField; } set { myField = value; } } } ... MyClass obj = new MyClass(); obj.MyField = 3;
C# 3.0부터는 자동 구현 프로퍼티가 가능함
public class NameCard { public String Name { get;set; } } .. //호출시에 NameCard nc = new NameCard { Name = "영국너구리" }
더불어 C# 7.0부터는 자동 구현 프로퍼티를 선언함과 동시에 초기화를 수행할 수 있음
public class NameCard { public string Name{ get; set; } = "Unknown"; public string PhoneNumber{ get; set; } = "000-0000"; }