[C# / .NET] Java와 다른 문법
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";
}