[C#] 클래스에 대한 이것저것
ASP.NET MVC 프레임워크를 사용하기 전에 C#에 대한 본질적인 이해가 더 중요하다고 생각됐다.
그래서 알아보는 C#의 클래스에 대한 갖가지 상식!
클래스 접근제한자
1. public
외부에서 자유롭게 접근 가능
public class A
{
public string str;
}
// Ok
public class B
{
public B(A a)
{
Console.Write(a.str);
}
}
이 코드에서는 에러가 발생하지 않는다.
2. private
선언 클래스 내부에서만 접근 가능
public class A
{
private string str;
}
// Error
public class B
{
public B(A a)
{
Console.Write(a.str);
}
}
// Error
public class C : A
{
public C()
{
Console.Write(str);
}
}
클래스 B의 생성자에서 A를 전달 받은 다음 A의 멤버 변수인 str에 접근하려고 한다.
이거 에러난다.
클래스 A를 상속 받은 클래스 C에서 A의 멤버 변수인 str에 접근하려고 한다.
이것도 에러난다.
3. protected
선언 클래스, 상속 클래스에서만 접근 가능
public class A
{
protected string str;
}
// Error
public class B
{
public B(A a)
{
Console.Write(a.str);
}
}
// Ok
public class C : A
{
public C()
{
Console.Write(str);
}
}
클래스 B의 경우는 A를 상속 받지 않았기 때문에 에러가 발생한다.
클래스 C의 경우는 A를 상속 받았기 때문에 에러가 발생하지 않는다.
4. internal
같은 어셈블리 내에서 접근 가능
namespace program1
{
internal class A
{
private string str;
}
public class B
{
public A a;
}
}
// Error
namespace program2
{
public class C
{
public program1.A a;
}
}
program2 어셈블리에서 program1 어셈블리의 클래스를 접근하려고 하면 에러가 발생한다.
* 여기서 어셈블리란?
하나의 단일한 단위로 존재하는 .NET의 실행 가능한 프로그램 또는 실행 프로그램의 일부이며 실행 및 배포의 단위이다.
C# 응용프로그램 작성의 결과로 생긴 .exe 파일이 하나의 어셈블리이며
클래스 라이브러리 작성의 결과인 DLL 도 하나의 어셈블리이다.
다른 어셈블리에 존재한다는 것을 표현하기 위해 다른 namespace를 사용했는데
namespace 가 다르다고 꼭 다른 어셈블리인 것은 아니다.
한 어셈블리 안에는 여러 개의 namespace가 존재할 수 있다.
virtual, abstract, interface
1. virtual
클래스의 속성, 메서드, 인덱서, 이벤트 등을 선언할 때 사용할 수 있다.
필요에 따라 override 될 수 있지만 필수는 아니다.
public class A
{
public virtual void Say()
{
Console.Write("으악");
}
}
// Ok
public class B : A
{
public override void Say()
{
Console.Write("으억");
}
}
// Ok
public class C : A
{
}
2. abstract
이 키워드가 붙은 클래스는 인스턴스화할 수 없다.
abstract로 선언된 속성이나 메서드는 반드시 override 되어야 한다.
abstract class A
{
public abstract void Say();
}
// Ok
public class B : A
{
public override void Say()
{
Console.Write("으억");
}
}
// Error
public class C : A
{
}
// Error
public class D
{
public D()
{
A a = new A();
}
}
클래스 A를 상속 받았지만 Say 메소드를 재정의 하지 않은 클래스 C는 에러를 발생시킨다.
클래스 D 에서 추상클래스 A를 인스턴스화 시키면 에러가 발생한다.
3. interface
대체적으로 abstract와 비슷하지만 멤버 변수를 사용할 수 없다.
대신 프로퍼티는 사용 가능하다.
interface A
{
void Say();
}
// Ok
public class B : A
{
public void Say()
{
Console.Write("으악");
}
}
// Error
public class C : A
{
}
// Error
interface D
{
public string str;
}
// Ok
interface E
{
public string str { get; set; }
}
클래스 C는 인터페이스 A를 상속 받았으나 Say 메소드를 재정의하지 않았기 때문에 에러를 발생시킨다.
인터페이스 D는 내부에 멤버 변수를 사용했기 때문에 에러를 발생시킨다.
인터페이스 E처럼 Property를 생성하는 것은 가능하다.
abstract와 interface의 쓰임새 차이
abstract는 주로 계층구조에서 사용되지만 interface는 서로 다른 계층이어도 같은 기능을 추가하고 싶을 때 사용 가능하다.
Property
객체지향 프로그래밍에서 정보 은닉을 목적으로 수많은 getter, setter를 만들어야하는 불편함을 해소하고자 C#에서 제공하는 기능이다.
클래스 내부에 멤버 변수를 선언하면 정보 은닉의 목적을 위해 아래와 같이 구현하는 것이 일반적이다.
class A
{
private int n;
public int getN()
{
return this.n;
}
public void setN(int n)
{
this.n = n;
}
}
class B
{
int b;
public B()
{
A a = new A();
a.setN(1);
b = a.getN();
}
}
그런데 Property를 사용하면 코드가 간결해지고 더욱 직관적이게 된다.
class A
{
private int n;
public int n
{
get { return n; }
set { n = value; }
}
}
class B
{
int b;
public B()
{
A a = new A();
a.n = 1; // set
b = a.n; // get
}
}
위의 예시처럼 별다른 로직이 없는 단순한 getter, setter는 더 짧은 코드로 표현할 수 도 있다.
class A
{
public int n { get; set; }
}