Table of Contents

C# vs Java
,

Java 개발자를 위한 C#!


출력문 Parameter 사용법 (string.Format)

//%d, %s 같이 지정할 필요없이 자동으로 형변환되어 출력 가능.
Console.WriteLine("{0} {1} {2}", 77, 3.141592, "Test");

//%05d, %.10f와 같은 표현
Console.WriteLine("{0:D5} {1:F10}", 77, 3.141592);

Data Type

Primitive/Reference Type 상관없이 모두 소문자로 시작!

Primitive Types
Data Type Size Range
sbyte 1byte -128 ~ 127
ushort 2byte 0 ~ 65535
uint 4byte 0 ~ 4294967295
ulong 2byte 0 ~ 18446744073709551615
Data Type Size Range
Decimal 16byte ±1.0*1-e=28 ~ ±7.9*10e28
수↔문자열 메소드
Java C#
Integer.parseInt(“”); int.Parse(“”);
s.toString(); s.ToString();
상수
Nullable 변수

int? a = null;
int b;
int? c;

Console.WriteLine(a);
//Console.writeLine(b); /* Error! */
//Console.writeLine(c); /* Error! */

var : Dynamic Type
enum

int to Enum

Method 활용

기본적으로 Java와 동일하게 Method의 Argument로 전달되는 값은 Call by value이다! 단, C#은 키워드를 통해 Call by reference를 이용할 수 있다!

여러 개의 반환 값이 필요할 때

Call by Reference

static void Main(string[] args)
{
	int a = 10, b = 20;

	Swap(ref a, ref b);
	Console.WriteLine(a+" "+b);
}

static void Swap(ref int a, ref int b)
{
	int temp = a;
	a = b;
	b = temp;
}

출력 전용 Parameter

static void Divide(int x, int y, out int quotient, out int remainder)
{
	quotient = x / y;
	remainder = x % y;
}

static void Main(string[] args)
{
	int x = 5;
	int y = 3;

	int q, r;
	Divide(x, y, out q, out r);
	Console.WriteLine(q+" "+r);
}

Method 이름은 같고 Argument 개수가 다를 때

Method Overloading

Variable Length Arguments (가변 길이 매개변수)

static void Main(string[] args)
{
	int result = Sum(1, 2, 3, 4, 5);
	Console.WriteLine(result);
}

static int Sum(params int[] args)
{
	int sum = 0;
	foreach (int n in args)
		sum += n;

	return sum;
}

Argument 자동 매칭 및 초기화

명명된 Arguments

static void Main(string[] args)
{
	PrintProfile(age : 33, name : "James");
}

static void PrintProfile(string name, int age)
{
	Console.WriteLine(name+" / "+age);
}

선택적 Arguments

Class 활용
this() 생성자

int a, b, c;
public MyClass()
{
	this.a = 777;
}

public MyClass(int b) : this()
{
	this.b = b;
}

public MyClass(int b, int c) : this(b)
{
	this.c = c;
}

접근 한정자

객체 상속 Type 검사

Mammal mammal = new Dog();
Dog dog;

if(mammal is Dog)
{
	dog = (Dog) mammal;
}

Method Overriding

Method 숨기기

//다형성과 관계 있는 모습이 보인다.

//Base가 부모, Derived가 자식 관계일 때
//public new void MyMethod() {}
Derived d = new Derived();
d.MyMethod(); //자식

Base b = new Derived();
b.MyMethod();

Paritial Class (분할 클래스)
Extension Method (확장 메소드)

public static class CLASSNAME
{
	public static TYPE METHODNAME(this TYPE PARAM_NAME /*확장할 Class or Type*/, PARAM, ...)
	{
		//
	}
}

using System;
using MyExtension;

namespace MyExtension
{
    public static class IntegerExtension
    {
        public static int Square(this int myInt)
        {
            return myInt * myInt;
        }

        public static int Power(this int myInt, int exponent)
        {
            int result = myInt;
            for (int i = 0; i < exponent; i++)
            {
                result *= myInt;
            }

            return result;
        }
    }
}

namespace ExtensionMethod
{
    class MainApp
    {
        public static void Main(string[] args)
        {
            Console.WriteLine(3.Square());
            Console.WriteLine(3.Power(3));

        }
    }
}

Struct (구조체)
Interface 활용
Interface를 상속하는 Interface
Abstract Class (추상 클래스)
Generic Programming (일반화 프로그래밍)
Parameter의 Type 제약시키기

GENERIC_METHOD/CLASS where T : CONSTRAINT

/* CONSTRAINT */
/*
  struct : 값 형식
  class : 참조 형식
  new() : Parameter가 없는 생성자
  기반_클래스_이름 : 기반 클래스의 파생 클래스
  인터페이스_이름 : 인터페이스 구현 명시. (여러개 명시 가능)
  U : 또 다른 Parameter "U"로부터 상속받은 클래스
*/

공통 기능이지만 다른 문법
"Hello, World!"로 살펴보는 전체적 구조

namespace HelloWorld {
	class MainApp()	{
		public static void Main() {
			Console.WriteLine("Hello World!");
		}
	}
}

class MainApp() {
	public static void main() {
		System.out.println("Hello World!");
	}
}

C#의 소스는 Class가 최상위 개념이 아니다!

C#의 모든 Method 첫자는 "대문자"로 시작한다!

배열 사용법

//int arr[] = new int[10]; /* Error! Java는 가능! */
int[] arr = new int[10]; /* 이것만 가능! */

//int[][] arr = new int[2][3]; /* Java */
int[,] = new int[2,3];

가변 배열 (Jagged Array)

int[][] arr1 = new int[3][];
arr1[0] = new int[]{ 1, 2, 3, 4, 5 };
arr1[1] = new int[]{ 10, 20, 30 };
arr1[3] = new int[]{ 400, 500 };

int[][] arr2 = new int[3][] { new int[]{ 1, 2, 3, 4, 5 }, new int[]{ 10, 20, 30 }, new int[]{ 400, 500 } };

foreach

int[] arr = {1,2,3};
for(int n : arr)
	System.out.println(n);

int[] arr = {1,2,3};
foreach(int n in arr)
	Console.WriteLine(n);

Random
Lambda

C#

Expression(식) Lambda

(PARAMETERS...) => EXPRESSION;

using System;

namespace ConsoleApplication1
{
    class Program
    {
        delegate int Calc(int a, int b);

        static void Main(string[] args)
        {
            Calc calc = (a, b) => a + b; //자동으로 Parameter Types 판단.
            /* delegate를 이용하면 아래와 같은 표현이다. */
            /*
            Calc calc = delegate(int a, int b)
                        {
                            return a + b;
                        };
            */

            Console.WriteLine(calc(5,6));
        }
    }
}

Statement(문) Lambda

(PARAMETERS...) => {
			STATEMENTS;
			...;
		   };

using System;

namespace ConsoleApplication1
{
    class Program
    {
        delegate int BigValue(int a, int b);

        static void Main(string[] args)
        {
            BigValue val =
                (a, b) =>
                {
                    return a > b ? a : b;
                };

            Console.WriteLine(val(10,20));
        }
    }
}

Func와 Action을 이용한 더 간편한 Anonymous Function 만들기

Func Delegate

using System;

namespace ConsoleApplication1
using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            /* Parameter 없이 반환값만 있는 경우 */
            Func<string> func1 = () => "Hello World";
            Console.WriteLine(func1());


            /* Parameter 및 반환값이 있는 경우 */
            Func<int, int, int> func2 =
                (a, b) =>
                {
                    int result = a > b? a : b;
                    return result;
                };
            Console.WriteLine(func2(10,20));
        }
    }
}

Action Delegate

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            /* Parameter 없는 경우 */
            Action act1 = () => Console.WriteLine("Hello World");
            act1();


            /* Parameter가 있는 경우 */
            Action<int, int> act2 =
                (a, b) =>
                {
                    int result = a > b? a : b;
                    Console.WriteLine(result+"가 더 크다!");
                };
            act2(10,20);
        }
    }
}

Expression Tree (식 트리)

Data Structure (자료구조)
ArrayList LinkedList, List
HashTable Dictionary
Type 명시 불필요 (= object)
(System.Collections)
Type 명시 필요
(System.Collections.Generic)
C#에만 있는 문법
Property

class 클래스이름
{
	TYPE FIELD이름;
	접근한정자 TYPE PROPERTY이름
	{
		get
		{
			return FIELD이름;
		}

		/* set 접근자를 구현하지 않으면 읽기 전용 */
		set
		{
			FIELD이름 = value; //value는 암묵적 매개 변수
		}
	}
	
}

자동 구현 Property

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MyName mn = new MyName();
            
            mn.Name1 = "James";
            Console.WriteLine(mn.Name1);

            mn.Name2 = "Luke";
            Console.WriteLine(mn.Name2);
        }
    }

    class MyName
    {
        //기본 Property 사용
        private string _name;
        public string Name1
        {
            get
            {
                return _name;
            }

            set
            {
                _name = value;
            }
        }


        //자동 구현 Property 사용
        public string Name2
        {
            get;
            set;
        }
    }
}

Peroperty & Constructor (프로퍼티와 생성자)

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MyProfile mp = new MyProfile()
            {
                Name = "James",
                Age = 77
            };

            Console.WriteLine("{0} {1}", mp.Name, mp.Age);
        }
    }

    class MyProfile
    {
        public string Name
        {
            get;
            set;
        }

        public int Age
        {
            get;
            set;
        }
    }
}

Anonymous Type (무명 형식)

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var x = new { Subject = "Math", Scores = new int[] {77,30,94,50} };

            Console.WriteLine(x.Subject);
            foreach (var scores in x.Scores)
            {
                Console.Write(scores+" ");
            }
        }
    }
}

Property of Interface (인터페이스의 프로퍼티)

Property of Abstract Class (추상 클래스의 프로퍼티)

using System;

namespace ConsoleApplication1
{
    abstract class Product
    {
        private static int serial = 0;
        public string SerialID
        {
            get
            {
                return String.Format("{0:d5}", serial++);
            }
        }

        abstract public DateTime ProductDate
        {
            get;
            set;
        }
    }

    class MyProduct : Product
    {

        public override DateTime ProductDate
        {
            get;
            set;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Product p = new MyProduct()
            {
                ProductDate = DateTime.Now
            };

            Console.WriteLine(p.SerialID + "/" + p.ProductDate);
            Console.WriteLine(p.SerialID + "/" + p.ProductDate);
        }
    }
}

Source 비교

Property 이용X Property 이용O
using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MyProfile mp = new MyProfile();
            mp.SetName("James");
            mp.SetAge(77);

            Console.WriteLine(mp.GetName()+"/"+mp.GetAge());
        }
    }

    class MyProfile
    {
        private string name;
        private int age;

        public string GetName()
        {
            return name;
        }

        public void SetName(string value)
        {
            name = value;
        }


        public int GetAge()
        {
            return age;
        }

        public void SetAge(int value)
        {
            age = value;
        }        
    }
}
using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MyProfile mp = new MyProfile
            {
                Name = "James",
                Age = 77
            };

            Console.WriteLine(mp.Name+"/"+mp.Age);
        }
    }

    class MyProfile
    {
        public string Name
        {
            get;
            set;
        }

        public int Age
        {
            get;
            set;
        }
    }
}
Indexer

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MyList list = new MyList();

            for (int i = 0; i < 5; i++)
                list[i] = i;

            for (int i = 0; i < list.Length; i++ )
                Console.WriteLine(i);

            Console.WriteLine("index 3 : "+list[3]);
        }
    }

    class MyList
    {
        private int[] arr;

        public MyList()
        {
            arr = new int[3];
        }

        public int this[int idx]
        {
            get
            {
                return arr[idx];
            }

            set
            {
                //Resize
                if (idx >= arr.Length)
                {
                    Array.Resize<int>(ref arr, idx + 1);
                    Console.WriteLine("Resized : " + arr.Length);
                }

                arr[idx] = value;
            }
        }

        public int Length
        {
            get
            {
                return arr.Length;
            }
        }
    }
}

foreach가 가능한 객체 만들기

using System;
using System.Collections;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MyList list = new MyList();

            for (int i = 0; i < 5; i++)
                list[i] = i;

            foreach (int e in list)
                Console.WriteLine(e);

            Console.WriteLine("index 3 : "+list[3]);
        }
    }

    class MyList : IEnumerable, IEnumerator
    {
        private int[] arr;
        int position = -1; //MoveNext() 때문!

        public MyList()
        {
            arr = new int[3];
        }

        public int this[int idx]
        {
            get
            {
                return arr[idx];
            }

            set
            {
                //Resize
                if (idx >= arr.Length)
                {
                    Array.Resize<int>(ref arr, idx + 1);
                    Console.WriteLine("Resized : " + arr.Length);
                }

                arr[idx] = value;
            }
        }

        public int Length
        {
            get
            {
                return arr.Length;
            }
        }


        /* 아래 3개의 Method는 IEnumerator의 Member */
        public object Current
        {
            get
            {
                return arr[position];
            }
        }

        public bool MoveNext()
        {
            if (position == arr.Length - 1)
            {
                Reset();
                return false;
            }

            position++;
            return position < arr.Length;
        }

        public void Reset()
        {
            position = -1;
        }


        /* 아래 Method는 IEnumerable의 Member */
        public IEnumerator GetEnumerator()
        {
            /* "yield return"은 arr[i]를 반환하고, 그 중단된 위치에서 반복을 이어간다. */
            for (int i = 0; i < arr.Length; i++ )
                yield return arr[i];
        }
    }
}

Delegate

ACCESS_MODIFIER delegate TYPE NAME(Param, ...);

예제

/* 결과를 출력한다는 공통된 기능을 갖고, 연산만 달라진다는 시나리오. */

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Calculator calc = new Calculator();
            del_calc calc_plus = new del_calc(calc.Plus);
            del_calc calc_minus = new del_calc(calc.Minus);

            Print(calc_plus, 1, 2);
            Print(calc_minus, 10, 20);
        }


        delegate int del_calc(int a, int b);

        static void Print(del_calc c, int a, int b)
        {
            int result = c(a, b);
            Console.WriteLine(result);
        }
    }

    class Calculator
    {
        public int Plus(int a, int b)
        {
            return a + b;
        }

        public int Minus(int a, int b)
        {
            return a - b;
        }
    }
}

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            //오름차순 버블 정렬
            int[] arr1 = { 3, 5, 1, 0, 8 };
            BubbleSort(arr1, new Compare(AscCompare));
            foreach (int i in arr1)
                Console.Write(i + " ");

            Console.WriteLine();

            //내림차순 버블 정렬
            int[] arr2 = { 4, 99, 32, 45, 0 };
            BubbleSort(arr2, new Compare(DescCompare));
            foreach (int i in arr2)
                Console.Write(i + " ");
        }


        delegate int Compare(int a, int b);

        static int AscCompare(int a, int b)
        {
            if (a > b)
                return 1;
            else if (a == b)
                return 0;
            else
                return -1;
        }

        static int DescCompare(int a, int b)
        {
            if (a < b)
                return 1;
            else if (a == b)
                return 0;
            else
                return -1;
        }

        static void BubbleSort(int[] arr, Compare cpr)
        {
            int i = 0;
            int j = 0;
            int temp = 0;

            for (i = 0; i < arr.Length - 1; i++ )
            {
                for (j = 0; j < arr.Length - (i + 1); j++)
                {
                    if (cpr(arr[j], arr[j + 1]) > 0)
                    {
                        temp = arr[j + 1];
                        arr[j + 1] = arr[j];
                        arr[j] = temp;
                    }
                }
            }
        }
    }
}

Delegate Chain

예제

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MyDelegate dele1 = null;
            dele1 += func1;
            dele1 += func2;
            dele1 += func3;
            dele1 -= func2;

            dele1();


            Console.WriteLine();


            MyDelegate dele2_1 = new MyDelegate(func1);
            MyDelegate dele2_2 = new MyDelegate(func2);
            MyDelegate dele2_3 = new MyDelegate(func3);

            MyDelegate dele2_all = null;
            dele2_all = (MyDelegate)Delegate.Combine(dele2_1, dele2_2, dele2_3);
            dele2_all = (MyDelegate)Delegate.Remove(dele2_all, dele2_2);

            dele2_all();
        }


        delegate void MyDelegate();

        public static void func1()
        {
            Console.WriteLine("첫번째");
        }

        public static void func2()
        {
            Console.WriteLine("두번째");
        }

        public static void func3()
        {
            Console.WriteLine("세번째");
        }
    }
}


using System;

namespace ConsoleApplication1
{
    class Program
    {
        Notifier notifier = new Notifier();
        EventListener listener1 = new EventListener("listener1");
        EventListener listener2 = new EventListener("listener2");
        EventListener listener3 = new EventListener("listener3");

        static void Main(string[] args)
        {
            Program program = new Program();

            program.Example1();
            program.Example2();
            program.Example3();
        }

        public void Example1()
        {
            Console.WriteLine("*** Example1 ***");

            notifier.EventOccured += listener1.SomethingHappend;
            notifier.EventOccured += listener2.SomethingHappend;
            notifier.EventOccured += listener3.SomethingHappend;
            notifier.EventOccured("You've got mail.");

            Console.WriteLine();

            //끊기
            notifier.EventOccured -= listener2.SomethingHappend;
            notifier.EventOccured("Download Complete.");

            Console.WriteLine();
        }

        public void Example2()
        {
            Console.WriteLine("*** Example2 ***");

            notifier.EventOccured = new NotifyDelgate(listener2.SomethingHappend) + new NotifyDelgate(listener3.SomethingHappend);
            notifier.EventOccured("Nuclear launch detected.");

            Console.WriteLine();
        }

        public void Example3()
        {
            Console.WriteLine("*** Example3 ***");

            NotifyDelgate noti1 = new NotifyDelgate(listener1.SomethingHappend);
            NotifyDelgate noti2 = new NotifyDelgate(listener2.SomethingHappend);

            notifier.EventOccured = (NotifyDelgate) Delegate.Combine(noti1, noti2);
            notifier.EventOccured("Fire!");

            Console.WriteLine();

            //끊기
            notifier.EventOccured = (NotifyDelgate) Delegate.Remove(notifier.EventOccured, noti2); //Delegate source, Delegate value
            notifier.EventOccured("OK");
        }
    }


    delegate void NotifyDelgate(string message);

    class Notifier
    {
        public NotifyDelgate EventOccured;
    }

    class EventListener
    {
        private string name;
        public EventListener(string name)
        {
            this.name = name;
        }

        public void SomethingHappend(string message)
        {
            Console.WriteLine(name+" / "+message);
        }
    }
}

Anonymous Method (익명 메소드)

DELEGATE_INSTANCE = delegate(PARAMETER, ...)
		    {
			//code
		    }

using System;

namespace ConsoleApplication1
{
    class Program
    {
        delegate int del_calc(int a, int b);

        static void Main(string[] args)
        {
            Print(
                delegate(int a, int b)
                {
                    return a * b;
                }
                , 5, 7);
        }

        static void Print(del_calc d, int a, int b)
        {
            Console.WriteLine(d(a,b));
        }
    }
}

Event

using System;

namespace ConsoleApplication2
{
    delegate void onClick(string what);

    class Program
    {
        //event EventType EventName
        public event onClick myClick;

        public static void Main(string[] args)
        {
            Program main = new Program();
            TestDelegate td = new TestDelegate();

            onClick deleMethod1 = new onClick(td.MouseClick);
            onClick deleMethod2 = new onClick(td.KeyBoardClick);

            //Event += Delegate
            main.myClick += deleMethod1;
            main.myClick += deleMethod2;

            main.myClick("Hello"); //두 Method에 전달됨.
        }
    }

    public class TestDelegate
    {
        public void MouseClick(string what)
        {
            Console.WriteLine("Mouse Click! " + what);
        }

        public void KeyBoardClick(string what)
        {
            Console.WriteLine("KeyBoard Click! " + what);
        }
    }
}

/* Ver.1 */
using System;

namespace ConsoleApplication2
{
    delegate void sendMessage(string message);

    class Program
    {
        public static event sendMessage sendMessageEvent;

        public static void Main(string[] args)
        {
            Program.sendMessageEvent += Program_sendMessageEvent;
            Program.sendMessageEvent("Hello, World!");
        }

        static void Program_sendMessageEvent(string message)
        {
            Console.WriteLine(message);
        }
    }

}

/* Ver.2 */
using System;

namespace ConsoleApplication2
{
    class Program
    {
        public static void Main(string[] args)
        {
            MyEventManager.sendMessageEvent += MyEventManager_sendMessageEvent;
            MyEventManager.SetOnSendMessage("Hello World!");
        }

        static void MyEventManager_sendMessageEvent(string message)
        {
            Console.WriteLine(message);
        }
    }

    class MyEventManager
    {
        public delegate void sendMessage(string message);
        public static event sendMessage sendMessageEvent;

        public static void SetOnSendMessage(string message)
        {
            if (sendMessageEvent != null)
                sendMessageEvent(message);
        }
    }
}

Event vs. Delegate

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MyNotifier noti = new MyNotifier();
            noti.Handler += new EventHandler(MyHandler);
            //noti.Handler("test");  /* Error! event는 객체 외부에서 호출 불가. */

            for (int i = 1; i < 30; i++)
                noti.DoSomething(i);
        }

        static public void MyHandler(string message)
        {
            Console.WriteLine(message);
        }
    }


    delegate void EventHandler(String message);

    class MyNotifier
    {
        public event EventHandler Handler;

        public void DoSomething(int num)
        {
            int temp = num % 10;
            if (temp != 0 && temp % 3 == 0)
                Handler(String.Format(num+" : 짝"));
        }
    }
}

LINQ (Language INtegrated Query)

using System;
using System.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] numbers = { 99, 2, 55, 1, 3, 77, 30, 20};

            var result =
                from n in numbers //어떤 집단?
                where n % 2 == 0  //어떤 조건?
                orderby n
                select n;

            foreach(int n in result)
                Console.WriteLine(n);
        }
    }
}

명명법
Visual Studio 2013 사용 Tip
  1. Eclipse처럼 Method 자동완성(Intelligence) 사용시 곧바로 자동 소괄호+매개 변수 설명을 보고싶다면 Visual Assist X를 사용하면 된다. (그런데 유료)
  2. Eclipse의 syso, Ctrl+Space를 치면 System.out.println()이 자동생성되는 것처럼 VS에도 같은 기능으로 코드 조각이라는 기능이 있다.
Eclipse vs Visual Studio (IDE 단축키)
Eclipse Visual Studio
자동 Package 추가
(Import/using)
Ctrl+Shift+O (대소문자 정확히 입력 후 맨 끝에서)
Ctrl+.
Alt+Shift+F10
자동 Interface & Abstract Class 요소 구현 (Header에 커서 두고)
Alt+Shift+F10
Method의 Argument 보기 Ctrl+Space Ctrl+Shift+Space
코드 자동 정렬 Ctrl+Shift+F Ctrl+K,F
줄 단위 Block Shift+↑/↓
주석
(//)
설정/해제 : Ctrl+/ (코드 바로 앞에) 설정 : Ctrl+K+C, 해제 : Ctrl+K+U
(줄 맨 앞에) 설정/해제 : /
주석
()
설정 : Ctrl+Shift+/
해제 : Ctrl+Shift+\
설정/해제 : Shift+8
줄 삭제 Ctrl+D Ctrl+Shift+L
줄 이동 Alt+↑/↓ (Block 미지정 상태에서)
Ctrl+X/L, Ctrl+V
줄 복사 Ctrl+Alt+↑/↓ (Block 미지정 상태에서)
Ctrl+C, Ctrl+V