728x90

윈폼에서 코드로 디자인

namespace CS_Windows_Forms
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
 
            myButton.Text = "코드에서 변경!";
            myButton.Width = 200;
 
            for (int i = 0; i < 5; i++)
            {
                Button btn = new Button();
                Controls.Add(btn);
                btn.Location = new Point(2080 + i * 30);
                btn.Text = i + " 동적 생성";
            }
        }
    }
}

결과 화면



폼 디자인 코드에서 생성자 정의하기

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
 
            Button btn = new Button();
            Controls.Add(btn);
            btn.Location = new Point(2080);
            Box box = new Box(btn);
            
        }
    }
    class Box
    {
        public Box(Button btn)
        {
            btn.Text = "버튼 전달";
        }
    }






생성자 정의하고 버튼으로 값 변경하기

namespace CS_Windows_Forms
{
    public partial class Form1 : Form
    {
        Box box;
 
        public Form1()
        {
            InitializeComponent();
 
            Button btn = new Button();
            Controls.Add(btn);
            box = new Box(btn);
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            box.Area();
        }
    }
    class Box
    {
        Button btn;
 
        public Box(Button btn)
        {
            this.btn = btn;
            btn.Text = "버튼 전달";
        }
 
        public void Area()
        {
            if (btn.Width > 250)
                MessageBox.Show("더 이상 늘릴 수 없습니다");
 
            else
            {
                btn.Width += 10;
                btn.Height += 10;
            }
        }
    }
}




static 키워드

static이라는 키워드를 붙인 변수 또는 메서드는 프로그램을 실행하는 순간에 메모리가 올라가게 된다.

이때는 객체의 생성없이 메서드


Code Snippet
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.Collections;
  7. using System.Threading;
  8.  
  9. namespace SScore
  10. {
  11.     class Test
  12.     {
  13.         public static int Abs(int n)
  14.         {
  15.             if (n < 0)
  16.                 return -n;
  17.  
  18.             else
  19.                 return n;
  20.         }
  21.     }
  22.  
  23.     class Program
  24.     {
  25.         static void Main(string[] args)
  26.         {
  27.             //Test test = new Test();
  28.             int num = Test.Abs(-10);
  29.             Console.WriteLine(num);
  30.         }
  31.     }
  32. }




C#의 구조체


c#에서도 구조체를 쓸 수 있다. c#에서는 구조체 멤버 변수도 기본적으로 private로 보호된다.


namespace SScore
{
    public struct MyPoint
    {
        public int x;
        int y;
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            MyPoint point;
            Console.WriteLine(point.x);
            Console.WriteLine(point.y); // 오류 : 보호 수준 때문에 'SScore.MyPoint.y'에 액세스할 수 없습니다.	
 
        }
    }
}


private 생성자

기본적으로 생성자는 public 접근 제한자를 쓰지만, 

생성자로 클래스의 인스턴스를 만들 수 없게 할 때는 private 생성자를 사용한다.

namespace SScore
{
    class Hidden
    {
        private Hidden();
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            Hidden hidden = new Hidden();   // 오류
        }
    }
}

위와 같이 메인 메소드에서 인스턴스를 생성하려고 하면 다음과 같은 오류를 출력한다.

오류	: 'SScore.Hidden.Hidden()'은(는) abstract, extern 또는 partial로 
            표시되어 있지 않으므로 본문을 선언해야 합니다.

private 생성자를 이용하는 이유는 다음과 같다.


  • 정적 멤버(static member)만 가지고 있을때
  • 팩토리 메서드 패턴에서 팩토리 메서드로만 인스턴트를 생성하게 하고 싶을 때 (디자인 패턴중의 하나로, 부모 클래스에서 숨겨진 자식 클래스의 인스턴스를 만드는 형태)



정적 생성자 (static constructor)

정적 생성자는 정적(static)요소를 초기화 할때에 사용된다.

정적 생성자를 만들 때는 접근 제한자와 매개변수를 사용하지 못한다.

class Sample
{
    public static int value;
 
    static Sample()
    {
        value = 10;
        Console.WriteLine("정적 생성자 호출");            
    }
}
 
class Program
{
    static void Main(string[] args)
    {
        Sample sample = new Sample();   // 이 때 한번만 호출
        Console.WriteLine();
        Console.WriteLine(Sample.value);
    }
}

출력 : 

정적 생성자 호출


10



readonly 키워드 (read only)

읽기 전용 키워드인 readonly로 변수를 선언하면 값을 변경할 수 없게 된다. 

class Sample
   {        
       public readonly int id=0;
 
       public Sample()
       {
           this.id++;
           Console.WriteLine("생성자 호출");            
       }
   }
 
   class Program
   {
       static void Main(string[] args)
       {
           Sample sample = new Sample();   
           Console.WriteLine(sample.id);
       }
   }

읽기 전용 필드의 값을 변경하려 할 때 다음과 같은 오류 메시지를 출력한다. 다만, 생성자에서는 readonly 키워드 변수도 값을 변경할 수 있다.



Getter와 Setter

값을 은닉화하면서 의도치 않은 값으로 초기화하는 걸 방지할 때에는 게터와 세터를 사용한다.

get 접근자는 값을 반환하고, set 접근자는 값을 할당한다.

class Unsigned
{
    private int num;
    public int Num
    {
        get { return num; }
        set
        {
            if (value > 0) { num = value; }
            else { Console.WriteLine("num변수는 양수여야 합니다."); }
        }
    }
}
 
class Program
{
    static void Main(string[] args)
    {
        Unsigned unsigned = new Unsigned();
        unsigned.Num = -10;            
    }
}

Output : 

num변수는 양수여야 합니다.




게터와 세터를 더 쉽게 쓰려면 prop라고 입력하고  tap키를 두번 누르면 코드 조각이 자동으로 생성된다.

public int MyProperty { getset; }


propfull을 입력한 상태에서 tap키를 두 번 누르면 다음 형태의 코드 조각이 자동으로 생성된다.

private int myVar;
 
        public int MyProperty
        {
            get { return myVar; }
            set { myVar = value; }
        }




상속

using System;
using System.Collections;
using System.Collections.Generic;
 
namespace Study
{
    class Animal
    {
        public string name;
        public void Eat()
        {
            Console.WriteLine("냠냠");
        }
        public void Sleep()
        {
            Console.WriteLine("쿨쿨");
        }
    }
 
    class Dog : Animal
    {
        public void Bark()
        {
            Console.WriteLine("왈왈");
        }
    }
    class Cat : Animal
    {
        public void Meow()
        {
            Console.WriteLine("냐옹");
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
 
            List<Animal> Animals = new List<Animal>()
            {
                new Dog(){name="멍멍이"}, new Cat(){name="냐옹이"}
            };
 
            foreach(var item in Animals)
            {
                Console.WriteLine(item.name);
                item.Eat();
                item.Sleep();
 
                ((Dog)item).Bark();
            }
        }
    }
}

위의 프로그램을 실행시키면 다음과 같은 예외가 발생한다.


출력결과 :

멍멍이

냠냠

쿨쿨

왈왈

냐옹이

냠냠

쿨쿨


처리되지 않은 예외: System.InvalidCastException: 'Study.Cat' 형식 개체를 'Study.

Dog' 형식으로 캐스팅할 수 없습니다.


((Dog)item).Bark();

List에 Dog와 Cat 클래스의 인스턴스가 같이 존재하기 때문에 Cat 형식 개체를 Dog 형식 개체로 형변환 할 때 오류가 발생하는 것이다.

이를 해결하기 위해서는 조건문을 통해 item이 Dog객체인지 Cat 객체인지를 판별하게 해야 한다. 


is 키워드를 사용하면 특정 클래스의 객체일 때 true를 반환하게 된다.

다음과 같이 foreach 구문의 내용을 변경하고 실행해보자.


foreach(var item in Animals)
            {
                Console.WriteLine(item.name);
                item.Eat();
                item.Sleep();
 
                if (item is Dog)
                    ((Dog)item).Bark();
 
                else
                    ((Cat)item).Meow();
            }

실행 결과 :

멍멍이

냠냠

쿨쿨

왈왈

냐옹이

냠냠

쿨쿨

냐옹



섀도잉 (Shadowing)


변수의 이름이 겹칠 때 자신과 가장 가까운 변수를 사용한다. 아래 프로그램에서는 메인 메소드 내부가 된다.

class Program
   {
       public static int num = 20;
 
       static void Main(string[] args)
       {
           int num = 40;
           Console.WriteLine(num);
       }
   }

출력 결과 :

40



하이딩(Hiding)과 오버라이딩(Overriding)


부모 클래스와 자식 클래스 사이에는 이를 Hiding 이라고 한다. 상속하는 멤버가 아닌 자신의 클래스 내부의 변수를 사용한다.

숨겨진 변수나 메소드를 쓸 때는, 부모로 형변환을 통해 쓸 수 있다.


Code Snippet
  1. using System;
  2. namespace Study
  3. {
  4.     class Parent
  5.     {
  6.         public int q = 10;
  7.     }
  8.  
  9.     class Child : Parent
  10.     {
  11.         public new string q = "20";
  12.     }
  13.  
  14.     class Program
  15.     {
  16.         static void Main(string[] args)
  17.         {
  18.             Child child = new Child();
  19.             Console.WriteLine(child.q);
  20.             Console.WriteLine("" + ((Parent)child).q);
  21.         }
  22.     }
  23. }


출력결과 

20

10


static void Main(string[] args)
        {
            Child child = new Child();
            Parent parent = child;

            Console.WriteLine(child.q);
            Console.WriteLine(parent.q);
        }


메소드 하이딩

숨기려면 new 키워드를 사용해 하이딩 함을 명확하게 알려주는 것이 좋다. (에러는 띄우지 않지만 경고를 띄움)

메서드는 변수와 달리, 이름이 겹칠 때 하이딩할지 오버라이딩 할지 결정할 수 있기 때문이다.

using System;
namespace Study
{
    class Parent
    {
        public int variable = 273;
 
        public void Method()
        {
            Console.WriteLine("부모 메서드");
        }
    }
 
    class Child : Parent
    {
        public new void Method()
        {
            Console.WriteLine("자식 메서드");
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            Child child = new Child();
            child.Method();
            ((Parent)child).Method();
        }
    }
}


메소드 오버라이딩

부모의 메서드를 virtual 키워드로 정의하면, 자식 클래스에서 override 될 수 있다.

이 때 자식의 메소드가 부모 메서드를 덮어 씌우고 새로 정의된다.

using System;
namespace Study
{
    class Parent
    {
        public virtual void Method()
        {
            Console.WriteLine("부모 메서드");
        }
    }
 
    class Child : Parent
    {
        public override void Method()
        {
            Console.WriteLine("자식 메서드");
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            Child child = new Child();
            child.Method();
            ((Parent)child).Method();
        }
    }
}

Output :

자식 메서드

자식 메서드




sealed 키워드


클래스에 적용하면 : 절대 상속하지 못하게 함

메서드에 적용하면 : 더 이상 오버라이드하지 못하게 함



abstract(추상) 키워드


클래스에 적용하면 : 무조건 상속해서 쓰게 함. 해당 클래스 자체에서 인스턴스를 만들수 없게 됨


메서드에 적용하면 

: 반드시 오버라이드해서 쓰게 함, 이 때 메서드는 본문을 선언할 수 없으므로, 중괄호 {}를 쓰지 않고 곧바로 세미콜론 ; 으로 문장을 마침.

  abstract 메서드 선언을 위해 클래스도 abstract 클래스가 되어야 함. 따로 virtual 키워드를 쓰지 않아도 됨




Generic

using System;
namespace Study
{
    class Wanted <T>
    {
        public T value;
        public Wanted(T value)
        {
            this.value = value;
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            Wanted<string> wantedString = new Wanted<string>("String");
            Wanted<int> wantedint = new Wanted<int>(12);
 
            Console.WriteLine(wantedString.value);
            Console.WriteLine(wantedint.value);
        }
    }
}

T는 형식매개변수(Type Parametor)를 뜻하며, 하나의 약속이다. 이와 같이 변수 value 자료형을 원하는 자료형으로 지정 가능하다.




Out 키워드

using System;

namespace Study
{
    class Program
    {
        static void Main(string[] args)
        {
            string s="0404";
            int output;

            bool result = int.TryParse(s, out output);

            if (result)
            {
                Console.WriteLine(output);
            }
            else
                Console.WriteLine("숫자로 변환불가");
        }
    }
}


'Study > C#' 카테고리의 다른 글

C# 예외처리, delegate  (0) 2017.04.10
C# 인터페이스  (0) 2017.04.07
c# 복습  (0) 2017.03.31
headfirst c#-wpf  (0) 2016.11.19
5/27 업무일지 c#학생성적관리(콘솔)  (0) 2016.05.27

+ Recent posts