midas+son의 크리에이티브(creative) 이야기

//파일 저장 - FileStream, StreamWriter, WriteAllText, WriteAllLines

//4가지 방법

//string 1줄

        private string saveData = "1.테스트\n2.진행중\r\n3.입니다.";

//\n 개행 \r 캐리지리턴 - 시스템마다 개행을 나타내는 문자가 달라서 적음 \r


//string배열

        private string[] saveData2 = { "1.테스트", "2.진행중", "3.입니다." };


//디렉터리(폴더) 경로 지정

        private const string path = "./save/test1/";   //요즘 많이 사용하는 방법 /

        private const string path2 = ".\\save\\test2"; //옛날부터 디렉터리 구분하는 방법 \\

        private const string path3 = @".\save\test3"; //@뒤에 있는 string은 디렉터리를 표시하는 것이라고 지정 - 최신


//1.FileStream

        public void SaveByFileStream(string fileName = "S_FileString.txt")

        {

            StringBuilder fullPath = new StringBuilder();

            fullPath.Append(path);

            fullPath.Append("/");

            fullPath.Append(fileName);

            //string fullPath = path + "/" + fileName;


            try

            {

            //상단에 using System.IO; 추가

            FileStream fs = new FileStream(

                fullPath.ToString(), 

                FileMode.Create, 

                FileAccess.Write);

            //Byte단위로 바꾸어 주어야 함.


            byte[] bytes = Encoding.UTF8.GetBytes(saveData);    //string문자가 UTF8인코딩으로 byte화

            fs.Write(bytes, 0, bytes.Length);    //byte 저장. 0부터 총 길이만큼

            fs.Close();


            }

            catch(DirectoryNotFoundException e)

            {

                Console.WriteLine("디렉터리가 없습니다. 생성합니다.");

                Directory.CreateDirectory(path);

                SaveByFileStream(fileName);

                return;

            }

            catch(Exception e)

            {

                Console.WriteLine(e);

                return;

            }

            Console.WriteLine("세이브 완료(SaveByFileStream)");

        }


        //2.StreamWriter

        public void SaveByFileStreamWriter(string fileName = "S_StreamWriter.txt")

        {

            StringBuilder fullPath = new StringBuilder();

            fullPath.Append(path2);

            fullPath.Append("/");

            fullPath.Append(fileName);

        


            try

            {

                //상단에 using System.IO; 추가

                FileStream fs = new FileStream(

                    fullPath.ToString(),

                    FileMode.Create,

                    FileAccess.Write);

                StreamWriter sw = new StreamWriter(fs);    //스트림을 만들어서 

                sw.WriteLine(saveData);    //일괄 저장

                sw.Close();

                fs.Close();


            }

            catch (DirectoryNotFoundException e)

            {

                Console.WriteLine("디렉터리가 없습니다. 생성합니다.");

                Directory.CreateDirectory(path2);    //디렉터리 생성

                SaveByFileStreamWriter(fileName);   //자기 자신 다시 부름

                return; //함수 종료

            }

            catch (Exception e)

            {

                Console.WriteLine(e);

                return;

            }

            Console.WriteLine("세이브 완료(SaveByFileStreamWriter)");

        }



        //3.WriteAllText

        public void SaveByWriteAllText(string fileName = "S_WriteAllText.txt")

        {

            StringBuilder fullPath = new StringBuilder();

            fullPath.Append(path3);

            fullPath.Append("/");

            fullPath.Append(fileName);

            //string fullPath = path + "/" + fileName;


            try

            {

                File.WriteAllText(fullPath.ToString(), saveData);  //핵심 - string 통째로 저장

            }

            catch (DirectoryNotFoundException e)

            {

                Console.WriteLine("디렉터리가 없습니다. 생성합니다.");

                Directory.CreateDirectory(path3);    //디렉터리 생성

                SaveByWriteAllText(fileName);   //자기 자신 다시 부름

                return; //함수 종료

            }

            catch (Exception e)

            {

                Console.WriteLine(e);

                return;

            }

            Console.WriteLine("세이브 완료(SaveByWriteAllText)");

        }


        //4.WriteAllLines

        public void SaveByWriteAllLines(string fileName = "S_WriteAllLines.txt")

        {

            StringBuilder fullPath = new StringBuilder();

            fullPath.Append(path2);

            fullPath.Append("/");

            fullPath.Append(fileName);

            //string fullPath = path + "/" + fileName;


            try

            {

                File.WriteAllLines(fullPath.ToString(), saveData2);    //핵심 - string 배열 저장

            }

            catch (DirectoryNotFoundException e)

            {

                Console.WriteLine("디렉터리가 없습니다. 생성합니다.");

                Directory.CreateDirectory(path2);    //디렉터리 생성

                SaveByWriteAllLines(fileName);   //자기 자신 다시 부름

                return; //함수 종료

            }

            catch (Exception e)

            {

                Console.WriteLine(e);

                return;

            }

            Console.WriteLine("세이브 완료(SaveByWriteAllLines)");

        }

//짧은게 쓰기에는 편하지만 준비과정이 길고 쓰기 불편하게 성능은 더 좋지 않을 까 한다.

//컬렉션(Collection), 제네릭 컬렉션(Generic Collection)


//가장 큰 차이점

//컬렉션은 아무거나 잡다하게 다 집어 넣어 사용 할 수 있고

//제네릭 컬렉션은 제네릭 타입<T>을 집어넣어 해당 타입만 컨트롤 하는 것이다.

//안정성이나 속도 면에서 제네릭 컬렉션이 좋다.


            //컬렉션 - 템플릿 없음

            //상단에 using System.Collections; 추가

            ArrayList array = new ArrayList(); //std::vector 비슷한 녀석

            array.Add(10);

            array.Add(20);

            array.Add(15.5f);

            array.Add("가나다");

            array.Add(c1);

            array.Add(s1);  //struct는 박싱이 일어난다.

            //자료형이나 class, struct 구분없이 전부 다 들어갈 수 있다.

            for (int i = 0; i < array.Count; ++i )

            {

                Console.WriteLine(array[i]);

            }

            Console.WriteLine();

            //그외

            //HashTable //std::map 과 비슷

            //Queue

            //Stack



//===================================================//

            //제네릭 컬렉션 - <T> 템플릿 형식

            //std::vector<T> 같은 녀석

            List<int> numList = new List<int>();  //타입이 지정되어야 한다.

            numList.Add(19);

            numList.Add(30);

            numList.Add(54);

            //numList.Add(1.15);  //타입이 안맞아 에러

            foreach(int node in numList)

            {

                Console.Write(node + " ");

            }

            Console.WriteLine();


            //std::list<> 같은 녀석

            LinkedList<int> linked = new LinkedList<int>();

            linked.AddLast(50);

            linked.AddLast(60);

            linked.AddLast(70);

            linked.AddFirst(40);

            foreach (int node in linked)

            {

                Console.Write(node + " ");  // 40 50 60 70

            }

            Console.WriteLine();

            

            //그외

            //Dictionary<key, value> //std::map

            //Queue<T>

            //Stack<T>



//struct (구조체) 생성

 

    //가비지 컬렉팅의 대상이 아니고

    //스택메모리에 할당되는 struct

    struct MyStruct

    {

        //구조체에서는 미리 할당이 안됨. class에서는 됨.

        //public int i = 10;  //에러 - 구조체에는 인스턴스 필드 이니셜라이저를 사용할 수 없습니다.

        public int i;

        public int j;


        //struct에서도 생성자를 몇가지 조건하에 만들 수있다.

        //1. 매개변수가 무조건 있을 것

        //2. 생성자 안에서 struct의 변수에 값을 모두 할당할 것


        //매개변수가 없는 생성자는 불가

        //public MyStruct()

        //{

        //}

        public MyStruct(int num1, int num2)    //인자 수가 꼭 변수 수에 맞추는 것은 아니다.

        {

            i = num1;

            j = num2;   //하나만 해도 안되고 변수 모두에 값을 할당해야 한다.

        }


        //함수는 그냥 만들 수 있다.

        public void Show()

        {

            Console.WriteLine("i : {0}, j : {1}", i, j);

        }

    }

//class생성

    class MyClass

    {

        public int i = 10;


        public void Show()

        {

            Console.WriteLine("MyClass i : {0}", i);

        }


        public override string ToString()

        {

            //return base.ToString(); //base는 부모 타입. object

            return base.ToString() +"는 i가 " + i + "입니다";

        }


        public override bool Equals(object obj)

        {

            //as로 캐스팅

            MyClass other = obj as MyClass;

            if(other != null)

            {

                if(other.i == this.i)

                {

                    return true;

                }

            }

            return false;

        }

    }


//object를 인자로 받는 Fuction함수 

static void Func1(object o)

{

MyClass my = o as MyClass;

if(my != null)

{

my.Show();

}

else

{

Console.WriteLine("MyClass가 아니다." + o.ToString() + "입니다");

}

 

 

 //메인 함수

        static void Main(string[] args)

        {

            //MyStruct s1;  //에러 - 할당 되지 않은 것은 사용 할 수 없다.

            //s1.Show();


            MyStruct s1 = new MyStruct();   //기본 생성자, 안만들어도 자동으로 있다.

            s1.Show();


            MyStruct s2;    //생성 없이 사용 방법

            s2.i = 5;       //변수에 모두 값을 할당 한다.

            s2.j = 6;

            s2.Show();      //그러면 new없이 사용 가능 하다.


            MyStruct s3 = new MyStruct(100, 200);    //별도의 생성자로 할당

            s3.Show();


            MyStruct s4 = s2;   //class같은 경우는 heap메모리에서

                                //같은 것을 참조하지만

            s2.i++;             //struct에서는 값 복사를 한다.(별개로 복사, 깊은 복사)

            s2.Show();

            s4.Show();    //결과가 다르다


//class 할당

            MyClass c1 = new MyClass(); //class는 무조건 new로 heap에 할당

            Console.WriteLine(c1.ToString());   //class 는 object 타입을 기본적으로 상속 받는다.


            MyClass c2 = new MyClass(); 

            c2.i = 10;


            if(c1 == c2)    //class는 ==로 비교하면 주소값을 비교 한다.

            {

                Console.WriteLine("c1과 c2는 같다.");

            }

            else

            {

                Console.WriteLine("c1과 c2는 다르다.");  //주소값이 다르기 떄문에 false

            }

//비교함수 재정의 하여 처리

            if (Object.Equals(c1, c2))  //MyClass의 public override bool Equals(object obj) 를 탄다.

            {

                Console.WriteLine("c1과 c2는 같다.");   //i값이 같아서 true

            }

            else

            {

                Console.WriteLine("c1과 c2는 다르다.");  

            }



            //object;

            //박싱언박싱(Boxing, Unboxing)

            //class나 struct나 기본적으로 object class를 상속받고 있어

            //object를 인자로 받는 함수에 인자로 들어 갈 수 있다.

            Func1(c1);  //class는 같은 heap 메모리에서 참조만 넘겨준다.

            Func1(s1);  //구조체를 object로 받으면 heap에 new 로 새로 생성된다.(본체는 stack에 남아있다.)

            //메모리 낭비. 복사체는 가비지컬렉터 기다림.


            Object obj = s1;    //박싱이 일어남.(stack에 있는 struct가 object 클래스에 들어가야 하므로 Stack에서 Heap으로 모두 복사된다.)

            MyStruct s5 = (MyStruct)obj; //언박싱(heap에 있는걸 Stack에 복사한다. 매우 리소스를 까먹으므로 안좋다.)


            //int, float같은 기본 형은 다 struct이다. 


            string str1 = "abc";

            string str2 = "abc";

            if(str1 == str2)

            {

                //class 타입은 주소값을 비교한다. 하지만...

                //string은 class 타입이지만 

                //너무 자주 사용되기에 이미 값비교로 override 되어있다.

                Console.WriteLine("str1 == str2는 참이다.");    //참으로 나온다.

            }

            else

            {

                Console.WriteLine("str1 == str2는 거짓이다.");

            }

}

//c#에서는 struct와 class가 많이 다르다.(c++에서는 거의 동일)

//c#의 메모리 구조

//c++에서는 stack메모리, heap 메모리와 함께 데이터 영역이 별도로 있었다.

//c#에서는 데이터 영여이 stack에 포함된다고 생각하자.

//----------------------------------------------------------------------------

//  stack 메모리(데이터 영역 포함)       

//----------------------------------------------------------------------------

//  사이즈가 작다.                                   

//  struct 선언(new해도 stack이다.)       

//  속도가 빠름.                          

//  지역변수, 함수 파라미터 관리(가비지 커렉터의 대상이 아니다.)

//  복사 시 깊은 복사가 이루어 진다.(값들이 다 새로 할당)

//----------------------------------------------------------------------------

//  heap 메모리

//----------------------------------------------------------------------------

// 사이즈가 크다. 램 메모리 그 자체라고 봐도 무방할정도로 크다. (c++에선 동적할당 new 한것들이 들어감)

// class 선언시 할당

// 속도가 좀 느림.

// 복사하면 참조 복사가 된다.

//----------------------------------------------------------------------------

// Boxing, Unboxing(박싱언박싱) - 중요

// stack메모리에서 heap메모리로 넘어가는 것이 Boxing

// heap메모리에서 stack메모리로 넘어가는 것이 UnBoxing

// stack에 있는 것들은 값 형식으로 되어있고(기본 형들( Int, float, double.....)과 enum, struct 등등)

// heap에 있는 것들은 참조 형식이라고 생각하자.(class string array....등등)

//정렬 Array.Sort


            //int 정렬

            int[] intArray = { 1, 40, 34, 23, 56, 53, 87, 85, 32, 10 };    //int 배열


            Array.Sort(intArray);    // 오름 차순으로 정렬 되어 고정(1 10 23 32 34 40 53 56 85 87)

            Array.Reverse(intArray);  // 역정렬 되어 고정(87 85 56 53 40 34 32 23 10 1)

//--------------------------------------------------------//

//별도의 class 정렬

class Pistol IComparable<Pistol> //Sort를 하려면 IComparable<T>가 있어야 한다. Interface 이다.

    {  

public int damage = 1;    //데미지 변수

public Pistol(int power)    //생성자

{

     damage = power;

}

        //IComparable<T> 를 상속받고 비교하는 함수를 만든다.

        public int CompareTo(Pistol other)//인자는 T값(템플릿)

        {

//데미지 별로 정렬 하겠다.

            //Sort할 때 앞으로 갈껀 -1, 뒤는 1, 같으면 0

            if(this.damage < other.damage)    

            {

                //쟈기가 적으면 앞으로

                return -1;

            }

            else if(this.damage > other.damage)

            {

                //쟈기가 크면 뒤로

                return 1;

            }

            //같으면 0

            return 0;

        } 

}


//main에서........

            Pistol[] guns = new Pistol[10];    //class 배열 공간 생성

            //랜덤객체 생성

            Random random = new Random();

            for (int i = 0; i < guns.Length; ++i )

            {

//데미지 랜덤 생성

                guns[i] = new Pistol(random.Next(100) + 1);

            }


            Array.Sort(guns);    //class 배열 정렬 가능 

//추상 클래스, 추상 함수(abstract)

    abstract class Gun

    {

        public int damage = 1;    //변수 지정 가능

        public int ammo = 5;


        //virtual public void Fire() = 0;   //c++에서의 순수가상함수. 자식이 무조건 오버라이드해야 하는 함수.

        public abstract void Fire();    //추상 함수를 가지면 class도 추상 클래스 여야 함. 자식이 무조건 오버라이드 해야함.

    } 


 //인터페이스(interface)

    interface IReload   //순수가상함수만 가지는 class 비스무리한 거...

    {

        //함수만 가능하다. abstract class와는 다르게 변수는 들어갈 수 없다.

        //int i = 0; //에러 - 인터페이스는 필드를 포함할 수 없습니다.


        void Reload();    //일반 함수는 접근 제한자가 없으면 private였으나 

//interface는 무조건 public 이다.

        //void Reload(){};  //구현부가 있으면 안된다.

    }

//테스트용 interface1

    interface IScope

    {

        void Aim();

    }

//테스트용 interface2

    interface IAim

    {

        void Aim();

    }

//class에서 상속 받음

class Pistol : Gun, IReload, IScope, IAim    //class상속은 무조건 1개만 되지만, interface는 다중 상속 가능(정부 순수 가상 함수이기에...)

    {

        public Pistol()    //생성자

        {

            damage = 1;

        }


        public Pistol(int power)    //생성자 인자1개

        {

            damage = power;

        }


        //가상함수 오버라이드

        public override void Fire()    //class Gun 에 있는 virtual함수 

        {

            ammo -= 1;

            Console.WriteLine("탕. {0}의 데미지", damage);

        }


        //인터페이스 함수 구현은 override를 안해도 된다.

        public void Reload()    //interface IReload 에 있는 순수 가상 함수이다.

        {

            ammo = 10;

            Console.WriteLine("장전 완료. ammo : {0}", ammo);

        }


        //interface IScope와 IAim에 둘다 Aim()함수가 있다.

        //아래 함수 자체로도 에러는 안난다. 어짜피 둘 다 추상 함수(순수 가상 함수)이므로..

        public void Aim()

        {

            Console.WriteLine("조준");

        }


        //하지만 나눠 사용할 경우가 있다. 

        //아래처럼 인터페이스 명을 앞에 붙여 쓰면 된다.

        void IAim.Aim() //public은 안쓴다.

        {

            Console.WriteLine("그냥 조준");

        }


        void IScope.Aim()

        {

            Console.WriteLine("조준경으로 조준");

        }

}


//main class

    class Program

    {

        static void Main(string[] args)

        {

            Pistol myGun = new Pistol(5);

            myGun.Fire();

            myGun.Reload();

            myGun.Aim();


            IScope scope = myGun as IScope; //요런 캐스팅이 되는 작업은 느리므로 자주 안하는 것이 좋다. 

            //myGun 이 IScope를 상속 받았으면 scope에 myGun이 들어간다. 아니면 null.

            if(scope != null)

            {

                scope.Aim();

            }


            Pistol bigGun1 = new BigGun(5);

            bigGun1.QuickFire1();

            bigGun1.QuickFire2();


            BigGun bigGun2 = new BigGun(5);

            bigGun2.QuickFire1();

            bigGun2.QuickFire2();

            bigGun2.QuickFireOld();


            IReload reloadable = bigGun1;   //캐스팅

            reloadable.Reload();


            if(reloadable is BigGun)

            {

                Console.WriteLine("reloadable은 BigGun");

            }

}

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

C#에서의 struct(구조체)와 class - 메모리 구조 차이, Boxing, Unboxing 개념  (0) 2016.05.11
정렬 Array.Sort, Array.Reverse  (0) 2016.05.10
랜덤  (0) 2016.05.09
함수인자 ref, out  (0) 2016.05.09
Console Title명, 창 크기  (0) 2016.05.08

랜덤

공부/C#2016. 5. 9. 13:32

            //랜덤

            Random random = new Random();

            int r = random.Next();    //랜덤 int 음수가 아닌 난수

            random.Next(10);    //지정한 값보다 작은 음수가 아닌 난수. 0~9

            random.Next(50, 100);    //50~99

            random.NextDouble();    //0.0 ~ 1.0


            byte[] byteArray = new byte[10];

            random.NextBytes(byteArray);    //배열에 모두 난수가 들어간다.



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

정렬 Array.Sort, Array.Reverse  (0) 2016.05.10
추상 클래스, 추상 함수(abstract), 인터페이스(interface)  (0) 2016.05.09
함수인자 ref, out  (0) 2016.05.09
Console Title명, 창 크기  (0) 2016.05.08
Console 입력 버퍼 검사  (0) 2016.05.08

함수인자 ref, out

공부/C#2016. 5. 9. 01:21

// 함수인자 ref, out


static void Main(string[] args)

{

            //int num;  //불가 -> 참조로 넘기려고 한다면 값이 할당되어있어야 한다.

            int num = 10;

            //class 변수의 경우는 new 되어있거나 , 

            //일반형 변수의 경우 값이 최기화되어 들어가 있어야 함.

            Test4(ref num); //참조 하는 변수라고 명시 

            Console.WriteLine("Test4 after : {0}", num);    //11


            int num2;    //out용 변수는 값이 할당되어있지 않아도 된다.

            Test5(out num2);

            Console.WriteLine("Test5 : {0}", num2);    //50


}


        /// <summary>

        /// ref 테스트

        /// </summary>. 파라미터를 참조로 받기

        /// <param name="num">참조하게 될 파라메터</param>

        static void Test4(ref int num)

        {

            Console.WriteLine("Test4 : {0}", num);

            num++;  //원래 값 자체를 변화시킨다.

        }


        /// <summary>

        /// out 출력용 함수

        /// </summary>

        /// <param name="num">출력값이 될 파라메터</param>

        static void Test5(out int num)

        {

            //num++;    //불가 -> 해당 값만 가져오는 거지 

                        //원래 변수 자체를 가져오는 것이 아니라 변화시킬 수 없다.

            num = 50;    //이 값이 원래 변수의 값이 된다.

        }

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

추상 클래스, 추상 함수(abstract), 인터페이스(interface)  (0) 2016.05.09
랜덤  (0) 2016.05.09
Console Title명, 창 크기  (0) 2016.05.08
Console 입력 버퍼 검사  (0) 2016.05.08
Console 커서 포지션(CursorPosition)  (0) 2016.05.08

/*

//c++ 에서는 아래의 같았다.

system("title Son's RPG");    //타이틀 명 수정 "Son's RPG" 을 넣는 것

system("mode con:cols=127 lines=36");   //창크기 127글자, 36글자

*/

//c# 에서는 아래와 같다.

Console.Title = "Son's RPG";    //타이틀 명 수정 "Son's RPG"을 넣는 것

Console.SetWindowSize(127,36);  //창크기 127글자, 36글자


//pixel 단위가 아니라 한 글자 크기 단위

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

랜덤  (0) 2016.05.09
함수인자 ref, out  (0) 2016.05.09
Console 입력 버퍼 검사  (0) 2016.05.08
Console 커서 포지션(CursorPosition)  (0) 2016.05.08
class - is , as  (0) 2016.05.08

//입력이 있을 때까지 While()문 내에 있기 위해

//c++ 에서는 _kbhit()을 사용했었다.

//c#에서는 Console.KeyAvailable 이다.


            while (true)

            {

//0.5초는 please press anykey 를 보여주고

                Console.SetCursorPosition(50, 31);

                Console.Write("please press anykey");

                System.Threading.Thread.Sleep(500);

                if (Console.KeyAvailable) break;    //입력 된게 있으면 while문 break;

//0.5초는 비어있게 하고

                Console.SetCursorPosition(50, 31);

                Console.Write("                       ");

                System.Threading.Thread.Sleep(500);

                if (Console.KeyAvailable) break;    //입력 된게 있으면 while문 break;

            }

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

함수인자 ref, out  (0) 2016.05.09
Console Title명, 창 크기  (0) 2016.05.08
Console 커서 포지션(CursorPosition)  (0) 2016.05.08
class - is , as  (0) 2016.05.08
델리게이트(delegate) - 대리자  (0) 2016.05.08