인터페이스
1 2 3 4 | interface ILogger // 첫글자 대문자로 적는건 약속 { } | cs |
인터페이스는 public
객체생성이 이뤄지지않는 껍데기
상속받은 자식클래스에서는 부모클래스에서 명시한 기능을 구현해야함
실제구현은 자식클래스
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Interface { interface ICar { void drive(string msg); } interface IAirplane { void fly(string msg); } class Machine : ICar { public void drive(string msg) { Console.WriteLine(msg); } } class Machine2 : IAirplane { public void fly(string msg) { Console.WriteLine(msg); } } class MainApp { static void Main(string[] args) { Machine m1 = new Machine(); Machine2 m2 = new Machine2(); } } }
죽음의 다이아몬드
: c#에서 클래스 다중상속을 허용하지 않는 이유는 죽음의 다이아몬드 때문이다.
프로그램에서 같은 구문이 두 가지 이상의 의미로 해석될 여지가 있어서는 안 된다
하지만, 인터페이스를 사용하면 다중상속이 가능하다.
인터페이스를 사용하는 이유는 다음과 같다.
- 자식단에서 구현할 메소드를 미리 구현
- 메소드의 이름만 물려받고 자식클래스에서 재정의
IComparable 인터페이스
인터페이스는 모두 대문자 I 로 시작한다. IComparable 인터페이스는 비교할 때 사용되는 규약이다.
using System; using System.Collections; using System.Collections.Generic; namespace Study { class Program { class Product { public string Name { get; set; } public int Price { get; set; } public override string ToString() { return Name + " : " + Price + "원"; } } static void Main(string[] args) { List<Product> list = new List<Product>() { new Product() {Name= "고구마", Price=1500}, new Product() {Name= "사과", Price=2400}, }; list.Sort(); foreach(var item in list) { Console.WriteLine(item); } } } }
위의 프로그램은 Sort() 메서드가 정렬의 기준을 알지 못하기 때문에 오류가 발생한다. 이러한 기준을 정해주기 위해 IComparable 인터페이스를 구현한다.
해당 클래스에서 IComparable 인터페이스를 상속받아 사용한다.
IComparable에 커서를 놓고 Ctrl + . 단축키를 누르면 다음과 같이 인터페이스를 쉽게 구현할 수 있다.
인터페이스 구현을 누르면 다음과 같이 CompareTo 메서드도 자동 생성된다.
public int CompareTo(object obj) { throw new NotImplementedException(); }
CompareTo 메서드를 다음과 같이 변경해보자. obj가 Product이면 가격을 비교해 반환하겠다는 뜻이다. 오름차순으로 정렬된다.
public int CompareTo(object obj) { return this.Price.CompareTo((obj as Product).Price); }
내림차 순으로 정렬하고 싶다면 다음과 같이 변경하면 될 것이다.
public int CompareTo(object obj) { return (obj as Product).Price.CompareTo(this.Price); }
using 키워드와 IDisposable 인터페이스
아래 예제에서는 IDisposable 인터페이스를 상속받은 클래스 Dummy의 인스턴스를 using 블록의 괄호 내에서 생성한다.
Dispose() 메서드를 따로 호출하지 않아도 using 블록을 벗어날 때 호출된다.
using System; namespace Study { class Program { class Dummy : IDisposable { public void Dispose() { Console.WriteLine("Dispose() 메서드 호출"); } } static void Main(string[] args) { using (Dummy dummy = new Dummy()) { } } } }
파일 입출력
using System.IO;
파일을 쓸 때 사용하는 StreamWriter는 IDisposable 인터페이스를 구현한 대표적인 클래스이다.
아래 파일 입출력 경로를 보면 @ 기호가 쓰인 것을 볼 수 있다.
문자열 내부에서 \ 기호는 특수한 의미를 지니기 때문에 원래는 \\를 사용해야 한다.
하지만 @ 기호를 붙여 문자열을 만들면 \\기호를 여러번 쓰지않아도 된다. 다만 내부에서 이스케이프 문자를 사용할 수 없게 된다.
using System; using System.IO; namespace Study { class Program { static void Main(string[] args) { string path = @"c:\tesst\test.txt"; string textValue = "시간 - " + DateTime.Now; try { File.WriteAllText(path, textValue); Console.WriteLine("읽은 문자열 : " + File.ReadAllText(path)); } catch (Exception) { Console.WriteLine("파일을 읽거나 쓸 수 없습니다"); } } } }
스트림으로 쓰기
큰 용량의 파일을 한꺼번에 읽고 쓰는 것은 시스템에 부담이 가기 때문에 파일을 한 줄씩 읽고 쓸 수 있는 다양한 방법이 있다.
StreamWrite 클래스를 이용하면 스트림으로 쓸 수 있다.
StreamWrite 클래스는 TextWriter의 상속을 받는다.
// 요약: // System.IO.TextWriter를 구현하여 특정 인코딩의 스트림에 문자를 씁니다. [Serializable] [ComVisible(true)] public class StreamWriter : TextWriter
TextWriter는 abstract class로 MarshalByRefObject, IDisposable의 상속을 받는다.
이를 통해 IDisposable 인터페이스를 구현한 클래스라는 것을 알 수 있다.
public abstract class TextWriter : MarshalByRefObject, IDisposable
다음은 StreamWrite 클래스로 파일에 여러 문자열을 쓰는 예제이다.
static void Main(string[] args) { string path = @"c:\test\test.txt"; using (StreamWriter writer = new StreamWriter(path)) { writer.WriteLine("안녕"); writer.WriteLine("여러줄을"); writer.WriteLine("입력해봄"); } Console.WriteLine(File.ReadAllText(path)); }
StreamReader 클래스로 한줄씩 읽기
아래는 잘못된 예제이다. 한 줄을 읽고 따로 값이 저장되지 않았기에 2번째 줄만 출력된다.
class Program { static void Main(string[] args) { string path = @"c:\test\test.txt"; using (StreamReader reader = new StreamReader(path)) { while (reader.ReadLine() != null) { Console.WriteLine(reader.ReadLine()); } } } }
바른 예
static void Main(string[] args) { string path = @"c:\test\test.txt"; using (StreamReader sr = new StreamReader(path)) { while (sr.Peek() >= 0) { Console.WriteLine(sr.ReadLine()); } } }
using을 사용하지 않은 예
class Program { static void Main(string[] args) { string path = @"c:\test\test.txt"; StreamReader reader = new StreamReader(path); string line; while ((line = reader.ReadLine()) != null) Console.WriteLine(line); } }
인터페이스, 내용 정리
인터페이스는 다중 상속이 가능하다.
public class MyConnection : Component, IDbConnection, IDisposable { }
인스턴스 변수를 가질 수 없다.
오류 : 인터페이스 멤버에는 정의를 사용할 수 없습니다.
interface IBasic { void TestMethod() { } }
인터페이스는 인스턴스 메서드를 가질 수 있다.
인터페이스는 클래스 변수를 가질 수 없다.
인터페이스는 클래스 메서드를 가질 수 없다.
인터페이스는 속성(Property)을 가질 수 있다.
'Study > C#' 카테고리의 다른 글
C# 네트워크 기본 (1) | 2017.04.12 |
---|---|
C# 예외처리, delegate (0) | 2017.04.10 |
C# 클래스, 메소드 (0) | 2017.04.04 |
c# 복습 (0) | 2017.03.31 |
headfirst c#-wpf (0) | 2016.11.19 |