개발 노트

c# 클래스 본문

프로그래밍/C#

c# 클래스

알 수 없는 사용자 2024. 2. 5. 22:57
//클래스 선언
public class 클래스이름
{
	//클래스 내용 구현
}


//클래스 레벨 메소드
class ClassNote
{
	static void Run()
    {
    	Console.WriteLine("ClassNote 클래스의 Run 메소드");
    }
    
    
    static void Main()
    {
    	Run(); // 메소드 레벨: 같은 클래스의 메소드 호출
        
        ClassNote.Run(); //클래스 레벨: 클래스, 메소드 형태로 호출
    }
}

[객체지향 프로그래밍]

코드 내의 모든 것을 객체로 표현하고자 함.

객체 = 속성(필드) + 기능(메소드)

ex) 사람 = 피부색 , 키 ,몸무게(속성) + 걷기, 뛰기(기능)

//클래스 구성

class Cat  
{
	// 속성 = 클래스의 변수 = 필드(Field)
	public string Name;
   	public string Color;
   
   // 기능 = 메소드
   public void Meow()
   {
   	Console.WriteLine("{0} : 야옹", Name);
   }
}

//객체 생성
class MainApp
    {
        static void Main(string[] args)
        {
            Cat kitty = new Cat(); // Cat클래스를 객체 kitty에 new연산자를 통해 대입
            kitty.Color = "하얀색"; // 대입된 kitty로 Color필드에 접근하여 값을 수정
            kitty.Name = "키티"; // 위와 동일
            kitty.Meow(); // Cat클래스에 있는 Meow()메소드에 접근
            Console.WriteLine("{0} : {1}", kitty.Name, kitty.Color); 
            //자리 표시자에 맞는 수정된 필드 값 대입
		}
    }

[생성자, 종료자]

생성자 : 객체가 생성될 때 호출

종료자 : 객체가 소멸될 때 호출

//생성자 선언
class Car
{
	public Car()
    {
    	Name = "";
        Color = "";
    }
    
    public Cat (string _Name, string _Color)
    {
    	Name = _Name;
    	Color = _Color;
    }
    
    public string Name;
    public string Color;
}

//생성자 호출 및 사용

Car suv = new Car(); // 생성자 버전1

Car audi = new Car( "아우디" , "청색");


//종료자

class 클래스 이름
{
	~클래스 이름()  // 종료자 
   {
   	//
   }
   
   // 필드
   // 메소드
}

[정적 필드, 메소드]

static으로 지정된 필드나 메소드는 클래스소속 

static으로 지정되지 않은 필드나 메소드는 인스턴스 소속

//정적 필드

class Global
{
   public static int Count = 0; // 정적 필드 선언
}

class ClassA
{
   public ClassA()
   {
       Global.Count++; // 정적 필드 접근
   }
}

class ClassB
{
   public ClassB()
   {
       Global.Count++; // 정적 필드 접근
   }
}

class MainApp
{
   static void Main()
   {
       Console.WriteLine($"Global.Count : {Global.Count}");
       
       new ClassA();
       new ClassA();
       new ClassB();
       new ClassB();

       Console.WriteLine($"Global.Count : {Global.Count}");
   }
}
> Global.Count : 0
> Global.COunt : 4


//정적 메소드
class MyClass
{
	public static void StaticMethod() // static 사용
   {
   	    // ...
   }
}

//...

MyClass.StaticMethod();  // 인스턴스 만들지 않고도 바로 호출 가능


// 인스턴스 메소드 //
class MyClass
{
	public void StaticMethod() // static 사용X
   {
   	    // ...
   }
}

//...

MyClass obj = new MyClass(); // 인스턴스 생성
obj.InstanceMethod(); // 인스턴스를 만들어야 호출 가능

[this]

객체 내부에서는 자신의 필드나 메소드에 접근 할 때 this 키워드 사용

lass Employee
   {
       private string Name;
       private string Position;

       public void SetName(string Name)
       {
           this.Name = Name;
       }

       public string GetName()
       {
           return Name;
       }

       public void SetPosition(string Position)
       {
           this.Position = Position;
       }

       public string GetPosition()
       {
           return this.Position;
       }
   }
    class MainApp
   {
       static void Main(string[] args)
       {
           Employee pooh = new Employee();
           pooh.SetName("Pooh");
           pooh.SetPosition("Waiter");
           Console.WriteLine($"Employee pooh - name :{pooh.GetName()}, position : {pooh.GetPosition()}");

           Employee tigger = new Employee();
           tigger.SetName("Tigger");
           tigger.SetPosition("Cleaner");
           Console.WriteLine($"Employee tigger - name:{tigger.GetName()}, position : {tigger.GetPosition()}");
       }
   }
}
> Employee pooh - name :Pooh, position : Waiter
> Employee tigger - name:Tigger, position : Cleaner

 

[this생성자]

자기 자신의 생성자를 가리키며 생성자의 코드 블록 내부가 아닌 앞쪽에서만 사용 가능

namespace ThisConstructor
{
    class MyClass
    {
        int a, b, c;

        public MyClass()
        {
            this.a = 5425;
            Console.WriteLine("MyClass()");
        }

        public MyClass(int b) : this()
        {
            this.b = b;
            Console.WriteLine($"MyClass({b})");
        }

        public MyClass(int b, int c) : this(b)
        {
            this.c = c;
            Console.WriteLine($"MyClass({b}. {c})");
        }

        public void PrintFields()
        {
            Console.WriteLine($"a:{a}, b:{b}, c:{c}");
        }
    }

    class MainApp
    {
        static void Main(string[] args)
        {
            MyClass a = new MyClass();
            a.PrintFields(); 
            Console.WriteLine(); 

            MyClass b = new MyClass(1);
            b.PrintFields();
            Console.WriteLine();

            MyClass c = new MyClass(10, 20);
            c.PrintFields();
        }
    }
}
> MyClass()
> a:5425, b:0 , c:0

> MyClass()
> MyClass(1)
> a:5425, b:1, c:0

> MyClass()
> MyClass(10)
> MyClass(10.20)
> a:5425, b:10 ,c:20

[상속]

-다른 클래스로부터 코드를 물려받아 쓰는 것

 

-새로 선언하는 클래스 이름 뒤에  : + 기반 클래스 이름 표기하여 상속

 

-물려주는 클래스: 기반/부모 클래스 , 물려받는 클래스 : 파생/자식 클래스

 

-상속을 받는 자식 클래스들은 기반 클래스의 모든 코드를 물려받아 더 많은 기능을 할 수 있다.

// 베이스 클래스
public class Animal
{
   public string Name { get; set; }
   public int Age { get; set; }
}

// 파생클래스
public class Dog : Animal
{       
   public void HowOld() 
   {
      // 베이스 클래스의 Age 속성 사용
      Console.WriteLine("나이: {0}", this.Age);
   }
}

public class Bird : Animal
{       
   public void Fly()
   {
      Console.WriteLine("{0}가 날다", this.Name);
   }
}

[오버로딩, 오버라이딩]

오버로딩 - 하나의 메소드로 여러가지를 구현하는 것(매개 변수의 개수 또는 타입만 다르게 정의하면 된다.)

 

오버라이딩 - 기반 클래스에서 파생된 메소드를 자식 클래스에서 재정의하는 것(다형성의 기반)

//오버로딩

namespace Overloading
{
    class MainApp
    {
        static int GetRectangleArea(int width, int height) //2개의 매개 변수 정수형int
        {
            return width * height;
        }

        static float GetRectangleArea(float width, float height) //2개의 매개 변수 실수형float
        {
            return width * height;
        }

        static int Sum(int a, int b) //2개의 매개 변수 정수형 int
        {
            return a + b;
        }

        static int Sum(int a, int b, int c)//3개의 매개 변수 정수형int
        {
            return a + b + c;
        }

        static void Main(string[] args)
        {
            Console.WriteLine(GetRectangleArea(20, 50));
            Console.WriteLine(GetRectangleArea(1.2f, 3.5f));
            Console.WriteLine(Sum(1, 2));
            Console.WriteLine(Sum(10, 11, 12));
        }
    }
}

//오버라이딩

namespace Overriding
{
    class ChessPiece
    {
        public virtual void Move() //부모 클래스에서는 virtual
        {
            Console.WriteLine("체스피스 : 이동할 수 없음");
        }
    }

    class Pawn : ChessPiece
    {
        public override void Move() //자식 클래스는 override
        {
            Console.WriteLine("폰 : 앞으로 한칸씩 이동, 초기에는 2칸 이동 가능");
        }
    }

    class Rook : ChessPiece
    {
        public override void Move() // 위와 동일
        {
            Console.WriteLine("룩 : 가로막고 있는 피스가 없는 한 종횡으로(상하좌우로) 원하는만큼 이동");
        }
    }

    class Bishop : ChessPiece
    {
        public override void Move() // 위와 동일
        {
            Console.WriteLine("비숍 : 가로막고 있는 피스가 없는 한 대각선방향으로 원하는만큼 이동");
        }
    }

    class MainApp
    {
        static void Main(string[] args)
        {
            ChessPiece piece = new ChessPiece();
            piece.Move(); 

            ChessPiece pawn = new Pawn();
            pawn.Move();

            ChessPiece rook = new Rook();
            rook.Move();

            ChessPiece bishop = new Bishop();
            bishop.Move();
        }
    }
}

[추상클래스]

추상클래스의 목적은  자식 클래스에서 공유할 수 있도록 추상 클래스의 공통적인 정의를 제공하는 것이다.

(추상클래스 안에서 접근 제한를 적지 않으면 모두 private)

 

추상 클래스 특징

1. new연산자를 이용하여 인스턴스 생성 불가

2. 오직 자식 클래스에서 상속을 통해서만 구현 가능

3. 추상 메소드와 추상 프로퍼티를 가질 수 있음.

 

추상 메소드 특징

1. 추상 메소드는 암시적으로 가상 메소드

2. 추상 메소드 선언은 오직 추상 클래스에서만 허용

3. 추상 메소드 선언할 때 static 또는 virtual 키워드 사용 불가

4. 추상 메소드는  실제 구현을 제공하지 않기에 메소드 본문이 없음.

//추상 클래스 및 메소드 선언

abstract class Animal
{
	public string name;
    public abstract void Move();
    
    public void Move2()
    {
    	Console.WriteLine("일반 메소드");
    }
}

// 상속 받아 추상 메소드 구현

class Dog : Animal
{
	public override void Move() //  자식 클래스는 override로 작성
    {
    	Console.WriteLine("네 발로 이동한다")'
    }
}

[인터페이스]

인터페이스에 속한 메소드는 모두 가상 메소드에 속한다.(virtual 키워드 지정 x  , 상속 받은 클래스에서 override 키워드 x)

 

인터페이스 특징

1. 메소드 , 프로퍼티, 인덱서, 이벤트만을 가질 수 있음.

2. 구현부가 없음.

3. 접근 제한자를 사용할 수 없고 모든 것이 public으로 선언

4. new 연산자를 이용해 인스턴스를 생성할 수 없지만 참조변수로는 만들기 가능

 

인터페이스 장점

1. 개발시간 단축

2. 표준화 가능

3. 서로 관계없는 클래스들에게 관계를 맺어 줌

4. 독립적인 프로그래밍 가능

 

*추상 클래스와 인터페이스 차이점 - 다중 상속의 유무(인터페이스 가능, 추상 클래스 불가능)

이유는 인터페이스는 클래스가 아니기 때문이다.

//인터페이스 선언 및 구현

interface ILogger // I를 붙여 인터페이스임을 나타내기 쉬움
{
	void WriteLog(string log);
}

class ConsoleLogger : ILogger //인터페이스 상속
{
	public void WriteLog(string log)
    {
    	Console.WriteLine("{0} {1}", DateTime.Now.ToLocalTime(), log);
    }
}

//인터페이스를 이용한 다형성

class Program
{
	static void Main(string[] args)
    {
    	ILogger logger = new ConsoleLogger(); //인터페이스로 객체생성
    }
}

[중첩 클래스]

클래스 내부에서 클래스를 정의하는 것을 중첩 클래스라 한다.

 

- 클래스를 논리적으로 그룹화

- 특정 클래스 내부에서만 사용되기에 코드를 더 쉽게 파악, 유지 관리가 쉬움

- 특정 클래스 내부에서만 사용되어 클래스 구조가 단순해짐.

 

ublic class School
{
  public void PrintSchool()
  {
    Console.WriteLine("PrintSchool() Method 호출");
  }

  // School 클래스의 내부 클래스입니다.
  public class Teacher
  {
    public void PrintTeacher()
    {
      Console.WriteLine("PrintTeacher() Method 호출");
    } 
  }
}

class Program
{
  static void Main(string[] args)
  {
    // School 클래스의 객체 생성
    School school = new School();
    school.PrintSchool();

    // 내부 클래스인 Teacher의 객체 생성
    School.Teacher teacher = new School.Teacher();
    teacher.PrintTeacher();
  }
}

> PrintSchool() Method 호출
> PrintTeacher() Method 호출
출처: https://developer-talk.tistory.com/473 [DevStory:티스토리]

내부 클래에서 외부 클래스 객체 생성이 가능하다.

또한 private로 선언된 외부 클래스 멤버 접근 가능하다

public class School
{
	private string name;
  public void PrintSchool()
  {
    Console.WriteLine("PrintSchool() Method 호출");
  }

  public class Teacher
  {
    public void PrintTeacher()
    {
      School school = new School(); // 외부 클래스로 객체 생성
      school.PrintSchool(); //외부 클래스 함수 접근
      school.name = "private 변수 접근" //private 변수에 접근
      Console.WriteLine("PrintTeacher() Method 호출" + shool.name);
    } 
  }
}
출처: https://developer-talk.tistory.com/473 [DevStory:티스토리]

 

외부 클래스에 static 필드와 함수가 있으면 객체 생성 없이 접근 가능

public class School
{
  private static string name = "ABC";

  private static void PrintSchool()
  {
    Console.WriteLine("PrintSchool() 메서드 호출");
  }

  public class Teacher
  {
    public void PrintTeacher()
    {
      School.PrintSchool();
      Console.WriteLine("School Name: " + School.name);
    } 
  }
}
출처: https://developer-talk.tistory.com/473 [DevStory:티스토리]

내부 클래스에 상속도 가능하다.

public class School
{
  public void PrintSchool()
  {
    Console.WriteLine("PrintSchool() 메서드 호출");
  }

  public class Teacher : School
  {
  }
}
출처: https://developer-talk.tistory.com/473 [DevStory:티스토리]

 

https://andjjip.tistory.com/134

 

[C#] 제네릭 프로그래밍(메서드, 클래스)

일반화 프로그램(제네릭 프로그램)은 데이터 형식을 일반화하는 기법이다. 예를들어 int 배열의 요소들을 출력하는 PrintArray(int[] a) 메서드를 만들었다고 가정해보자. 그런데 double 배열도 출력할

andjjip.tistory.com

[제네릭]

제네릭은 코드의 재사용성과 유연성을 향상해주는 도구이다.

데이터 형식을 일반화 하여 재사용 가능한 코드를 작성 할 수 있게 도와준다.

다양한 형식의 데이터를 처리하는 메서드와 클래스를 작성가능하고 컴파일 시점에서 안정성을 보장해 준다.

 

제네릭 언제 사용되는가?

- 여러 데이터 형식에 대해 동일한 로직을 적용해야 할 때

- 컬렉션 타입에서 다양한 데이터 형식을 저장하고 관리해야 할 때

- 데이터 형식에 따라 다른 연산을 수행해야 할 때

class Program
{
    static void ArrayIntPrint(int[] Num)// 정수 배열 
    {
        for (int Temp = 0; Temp < Num.Length; ++Temp)
        {
            Console.Write("{0} ", Num[Temp]);
        }
        Console.WriteLine();
        //foreach (int Temp in Num)
        //{
        //    Console.WriteLine("{0}", Temp);
        //}
    }

    static void ArraydoublePrint(double[] Num)// 실수 배열
    {
        for (int Temp = 0; Temp < Num.Length; ++Temp)
        {
            Console.Write("{0} ", Num[Temp]);
        }
        Console.WriteLine();
    }

    static void ArrayStringPrint(String[] Num) // 문자열 배열
    {
        for (int Temp = 0; Temp < Num.Length; ++Temp)
        {
            Console.Write("{0} ", Num[Temp]);
        }
        Console.WriteLine();
    }
    ================================================================================
    
      static void ArrayPrint<T>(T[] Num)// *제네릭 T 타입 배열 (위에 모든 배열을 포함한다)
    {
        for (int Temp = 0; Temp < Num.Length; ++Temp)
        {
            Console.Write("{0}  ", Num[Temp]);
        }
        Console.WriteLine();
    }

인자가 2개일 때

 static void ArrayPrint<T>(T[] Num)
    {
        for (int Temp = 0; Temp < Num.Length; ++Temp)
        {
         Console.Write("{0}  ", Num[Temp]);
        }
        Console.WriteLine();
    }

    static void ArrayIntCopy(int[] Dst, int[] Src) // 정수형 배열 2개의 인자
    {
        for(int Temp = 0; Temp < Dst.Length; ++Temp)
        {
            Dst[Temp] = Src[Temp];
        }
    }

    static void ArraydoubleCopy(double[] Dst, double[] Src)// 실수형 배열 2개의 인자
    {
        for (int Temp = 0; Temp < Dst.Length; ++Temp)
        {
            Dst[Temp] = Src[Temp];
        }
    }
    ================================================================================
       static void ArrayPrint<T>(T[] Num)
    {
        for (int Temp = 0; Temp < Num.Length; ++Temp)
        {
         Console.Write("{0}  ", Num[Temp]);
        }
        Console.WriteLine();
    }
    static void ArrayCopy<T>(T[] Dst, T[] Src)// 정수형 실수형을 포함하는 T타입의 2개의 인자
    {
        for (int Temp = 0; Temp < Dst.Length; ++Temp)
        {
            Dst[Temp] = Src[Temp];
        }
    }

제네릭은 두 개를 한꺼번에도 선언이 가능하다.

class Program
{
    static void TwoPrint<T1, T2>(T1 Arg1, T2 Arg2)
    {
        Console.WriteLine(Arg1);
        Console.WriteLine(Arg2);
    }
    static void Main(string[] args)
    {
        TwoPrint(3, 2.1);
        TwoPrint("헬로", 4.0f);
    }
}

[제네릭 클래스]

class MyClass<T>
{
	public T x; //T타입의 변수 x
    public T Dosomething(T p) { ... }//T 타입의 함수
}

MyClass<int> x = new Myclass<int>(); // T타입을 int타입으로
Myclass<string> s = new MyClass<string>(); //T 타입을 string타입으로

class Myclass
{
	public int x; //변경된 int형으로 변수 설정
    public int Dosomething(int p) { ... } //변경된 int형으로 함수 설정
}

======================================================================================
public class FACT //일반 클래스
{
    public int Value;
    public void Print()
    {
        Console.WriteLine("FACT Value = {0}", Value);
    }
}

public class FACT<T> //제네릭 클래스
{
    public int Value;
    public void Print()
    {
        Console.WriteLine("FACT Value = {0}", Value);
    }
}
========================================================================================
class FACT<T1, T2> //2개의 인자 제네릭 클래스
{
    public T1 Value1;
    public T2 Value2;
    public void Print()
    {
        Console.WriteLine("FACT Value = {0}, {1}", Value1, Value2);
    }
}
class Program
{
    static void Main(string[] args)
    {
        FACT<int, string> obj = new FACT<int, string>();
        obj.Value1 = 100;
        obj.Value2 = "서맛트 팩토리";
        obj.Print();
    }
}

 

https://huiyu.tistory.com/entry/C-%EA%B8%B0%EC%B4%88-%EC%9D%B4%EB%B2%A4%ED%8A%B8%EC%99%80-%EB%8D%B8%EB%A6%AC%EA%B2%8C%EC%9D%B4%ED%8A%B8-Event-Delegate

 

C# 기초 - 이벤트와 델리게이트 (Event & Delegate)

Delegates(델리게이트) - Delegate는 대리자라고도 하며, 메서드에 대한 참조를 갖는 형식이다. - 함수포인터나 콜백과 동일한 동작으로 delegate를 호출하면 참조하고 있는 메서드가 호출된다. - 참조하

huiyu.tistory.com

[델리게이트]

대리자라고도 칭하며, 메서드에 대한 참조를 갖는 형식이다.

함수포인터나 콜백과 동일한 동작으로 델리게이트를 호출하면 참조하고 있는 메서드가 호출된다.

참조하는 함수의 반환 형식 및 매개 변수를 사용하여 선언한다.

*선언한 함수 형식이 일치하는 메서드에 대해서만 참조가능 하다.

public delegate [반환형식] [이름] (매개변수) // 기본 선언 형식
public delegate void ThresholdReachedEventHandler(object sender, ThresholdReachedEventArgs e);//예제
====================================================================================================
namespace ConsoleApplication
{
    delegate int FuncDelegate(int a, int b); //대리자 설정

    class Program
    {
        static int Plus(int a, int b)
        {
            return a + b;
        }
        
        static int Minus(int a, int b)
        {
            return a - b;
        }

        static void Main(string[] args)
        {
            FuncDelegate plusDelegate = Plus; //plus함수 대리자에 삽입
            FuncDelegate minusDelegate = Minus;//minus함수 대리자에 삽입

            Console.WriteLine(plusDelegate(5, 10)); 
            Console.WriteLine(minusDelegate(20, 10));
        }
    }
}
>15
>10

하나의 델리게이트는 여러개의 함수를 등록하고 호출할 수 있는 델리게이트 체인을 지원한다.

namespace ConsoleApp1
{
    delegate void FuncDelegate(string str); // 대리자 설정

    class Program
    {
        static void Func1(string str) //함수1
        {
            Console.WriteLine("Helo1 : " + str);
        }
        static void Func2(string str)//함수2
        {
            Console.WriteLine("Helo2 : " + str);
        }
        static void Func3(string str)//함수3
        {
            Console.WriteLine("Helo3 : " + str);
        }
        static void Func4(string str)//함수4
        {
            Console.WriteLine("Helo4 : " + str);
        }
        static void Main(string[] args)
        {
            FuncDelegate plusDelegate = null;
            plusDelegate += Func1;// +=연산자로 함수를 등록 (-=는 제거)
            plusDelegate += Func2;
            plusDelegate += Func3;
            plusDelegate += Func4;

            plusDelegate("Text");
        }
    }
}
>Hello1 : Text
>Hello2 : Text
>Hello3 : Text
>Hello4 : Text

[이벤트]

객체에 특정 작업의 실행을 알리는 메세지, 예를 들어 사용자와의 상호작용과 같은 처리이다

ex) 버튼을 터치했을 경우나 속성값 변경등의 사건 

 

*이벤트는 일반적으로 delegate model을 기반으로 하며, 이는 관찰자 디자인 패턴(Observer Design Pattern)을 따른다.

(Observer Design Pattern :  구독자(Subscriber)가 공급자(Provider)를 등록하고 공급자(Provider)로부터 알림을 수신하는 데 사용)

 

- 이벤트를 발생시키는 개체(Object)를 'event sender'라고 하며, event sender는 어떤 개체(Object)나 함수(Method)를 수신하거나 처리할 지 모른다. 일반적으로 이벤트는 event sender의 멤버이다

class Counter
{
    public event EventHandler ThresholdReached; // 이벤트 선언

    protected virtual void OnThresholdReached(EventArgs e)
    {
        EventHandler handler = ThresholdReached;
        handler?.Invoke(this, e);
    }
    // provide remaining implementation for the class
}

 일반적으로 이벤트를 발생 시키기 위해 'protected' 및 'virtual' 이라고 표시된 메서드를 추가,  함수에서 EventHandler를 호출하고 있다.   -> On(EventName) 형태, 위 예제에선 OnThresholdReached 함수
 - 메서드에서 EventArgs 형식이나 파생형식의 이벤트 데이터를 지정하는 매개변수 사용하여 선언, 이벤트 발생시 필요한 데이터를 주고받을 수 있다.(데이터가 필요없는 경우 EventArgs를 사용, EventArgs는 모든 이벤트 클래스의 기본 형식이다.)
 * 여기서 EventHandler는 Delegate이다. Delegate임으로 여기에 연결된 함수들은 호출(Invoke)와 동시에 호출되게 된다.

 

 

'프로그래밍 > C#' 카테고리의 다른 글

c# 배열  (0) 2024.02.06
알람 작업  (0) 2024.01.31
C# 기초 문법 정리  (0) 2024.01.24
C# 자료형  (0) 2024.01.24
바이너리파일 공부하기  (0) 2022.04.22