DateTime 으로 시간을 확인 할 수 있지만, Stopwatch 를 통해 경과 시간을 확인 할 수 있습니다.

내부 요소를 통해 아래의 방법대로 표현도 가능합니다.

 

 

using System;
using System.Diagnostics;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch stopWatch = Stopwatch.StartNew(); //객체 만들자마자 Start()까지 실행됨
            
            while (stopWatch.ElapsedMilliseconds < 5000) //5초
            {
                try
                {
                    using (TcpClient tcpClient = new TcpClient()) //연결만 확인.
                    {
                        Task task = tcpClient.ConnectAsync("127.0.0.1", 8080); //연결할 주소
                        if (task.Wait(3000) && tcpClient.Connected) //연결 확인
                        {
                            tcpClient.Close();
                            break;
                        }
                    }
                }
                catch (Exception ex)
                {
                    //Console.WriteLine(ex); //서버 없으면 오류나서 주석처리
                }

                Console.WriteLine($"tick: {stopWatch.ElapsedTicks}");
                Console.WriteLine($"milliseconds: {stopWatch.ElapsedMilliseconds}");

                TimeSpan timeSpan = stopWatch.Elapsed;
                Console.WriteLine($"기본: {timeSpan}");
                Console.WriteLine($"초: {timeSpan.TotalSeconds}"); //전체 초 단위
                Console.WriteLine($"ms: {timeSpan.TotalMilliseconds}"); //전체 밀리초 단위
                Console.WriteLine($"포맷: {timeSpan:hh\\:mm\\:ss\\.fff}"); //00:00:00.000

                Console.WriteLine();
            }

            Console.ReadLine();
        }
    }
}

오랜만에 기본기에 대해 생각을 해보게 되었습니다.

값 복사 형식과 참조 형식.. (잊고 있던 포인터..)

코드에 대부분 클래스를 사용하다보니 잊고 있었는데 복습할 겸 글을 남겨봅니다.

가독성을 위해 foreach 를 사용하려고 하는데 구조체에 대해서는 메모리 낭비가 발생 되고,

foreach 내부에서 원본의 값을 수정할 수 없다는 단점이 있더군요..!

추가로 배열 사이즈 변경도 남겨봅니다.

 

 

using System;
using System.Collections.Generic;

namespace ConsoleApp2
{
    class Program
    {
        struct ValueType
        {
            public int a;
            public int b;
        }

        class ReferenceType
        {
            public int a;
            public int b;
        }

        static void Main(string[] args)
        {
            ValueType valueType; //new ValueType() 없이 사용 가능.
            valueType.a = 1;
            valueType.b = 2;

            ValueType valueType2 = valueType; //값 복사됨.
            valueType2.a = 3;
            valueType2.b = 4;

            ReferenceType referenceType = new ReferenceType(); //반드시 메모리 할당 필요
            referenceType.a = 1;
            referenceType.b = 2;

            ReferenceType referenceType2 = referenceType; //같은 메모리 바라봄
            referenceType2.a = 3;
            referenceType2.b = 4;

            Console.WriteLine("valueType : {0} {1}", valueType.a, valueType.b);
            Console.WriteLine("valueType2 : {0} {1}", valueType2.a, valueType2.b);

            Console.WriteLine("referenceType : {0} {1}", referenceType.a, referenceType.b);
            Console.WriteLine("referenceType2 : {0} {1}", referenceType2.a, referenceType2.b);

            List<ValueType> valueTypeList = new List<ValueType>();
            List<ReferenceType> referenceTypeList = new List<ReferenceType>();

            //ValueType은 foreach에서 값 변경이 불가능하다, 또한 메모리 낭비가 발생 될 수 있다.
            foreach (ValueType sub in valueTypeList)
            {
                Console.WriteLine("{0} {1}", sub.a, sub.b);
                //sub.a = 40; //구조체는 오류 발생. 복사 값이므로 원본을 바꿀 수 없어 컴파일 오류.
            }

            foreach (ReferenceType sub in referenceTypeList) //foreach 도 참조형태 - 원본 값 바뀜
            {
                Console.WriteLine("{0} {1}", sub.a, sub.b);
                sub.a = 40; //원본 값 변경 됨.
            }

            ValueType[] valueTypeArray = null;
            Array.Resize(ref valueTypeArray, 5); //new ValueType[5]

            for (int i = 0; i < valueTypeArray.Length; ++i)
            {
                Console.WriteLine("배열 개수 : {0}", i + 1);
            }

            Console.ReadLine();
        }
    }
}

Xml 구조 읽는 방법 예제

 

결과

 

using System;
using System.Xml;

class Test
{
    static void Main()
    {
        string testData =
                "<main>" +
                " <sub attribute1=\"SubAttribute\">" +
                "  <field name=\"first\">1</field>" +
                "  <field name=\"second\">" +
                "   <test>" +
                "    2" +
                "   </test>" +
                "  </field>" +
                " </sub>" +
                "</main>";

        XmlDocument xml = new XmlDocument();

        //파일 경로로 읽는 방식
        //xml.Load("파일 경로");

        //string 읽는 방식
        xml.LoadXml(testData);

        //<sub> 가져오기
        XmlNode subNode = xml.SelectSingleNode("main/sub"); //첫 번째 노드 가져옴

        //<sub> attribute1 가져오기
        string attribute1 = subNode.Attributes["attribute1"]?.Value;
        Console.WriteLine($"attribute1 : {attribute1}");

        //<sub><field> 가져오기
        XmlNodeList fieldList = subNode.SelectNodes("field"); //Node의 Node 방식

        //<field> 값들 순회
        foreach (XmlNode node in fieldList)
        {
            string innterText = node.InnerText; //순수 값.
            string innerXml = node.InnerXml; //xml 값 전체

            Console.WriteLine($"innerText: {innterText}, innerXml: {innerXml}");
        }

        //번외) 항상 첫 번째 값을 가져옴 (field가 여러개)
        string x = subNode["field"].Attributes["name"]?.Value; //"first"
        Console.WriteLine($"first node : {x}");
    }
}

Base64는 byte 배열을 읽는 방식을 의미합니다. (보통 우리가 사용하는 UTF8, ASCII 등이 있지요)

Base64는 3byte (24bit) 단위로 자르고, 6bit씩을 취해 해당 값에 매칭되는 base64테이블로 매핑해줍니다.

이 때, 원문이 없는 경우는 "=" 문자열을 넣어 길이를 채워줍니다.

아래는 aB1@ 를 base64로 변환 한 결과입니다.

 

Base64 Table : ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

 

base64 나눠지는 형식

 

 

일단 C# 에서 제공되는 코드가 있는데 내부 구현이 궁금하여 테스트 해보게 되었습니다.

 

[C# base64 기존 제공]

string text = "aB1@"; //원본
byte[] bytes = Encoding.UTF8.GetBytes(plainText); //원하는 인코딩으로 byte 만들기
string base64String = Convert.ToBase64String(bytes); //byte배열 -> base64 텍스트 변환
byte[] base64bytes = Convert.FromBase64String(base64String); //base64 텍스트 -> byte배열 변환
string originText = Encoding.UTF8.GetString(base64bytes); //원본과 일치

 

 

[C# 직접 구현 - 4Byte int 형으로 비트 값 연산에 사용 (GPT 도움..!)]

using System;
using System.Collections.Generic;
using System.Text;

class Test
{
    private const string table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    private const string plainText = "aB1@";

    static void Main()
    {
        byte[] bytes = Encoding.UTF8.GetBytes(plainText);

        string base64Text = Base64Encoding(bytes); //직접 구현
        string base64Text2 = Convert.ToBase64String(bytes); //기존 제공

        Console.WriteLine("base64 텍스트 : " + base64Text);
        Console.WriteLine("base64 텍스트2 : " + base64Text2);

        byte[] base64bytes = Base64Decoding(base64Text); //직접 구현
        byte[] base64bytes2 = Convert.FromBase64String(base64Text2); //기존 제공

        Console.WriteLine("원본 복원 : " + Encoding.UTF8.GetString(base64bytes));
        Console.WriteLine("원본 복원2 : " + Encoding.UTF8.GetString(base64bytes2));
    }

    private static string Base64Encoding(byte[] bytes)
    {
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < bytes.Length; i += 3)
        {
            int value = 0;
            int paddingCount = 0;

            //3byte씩 합쳐주기
            for (int j = i; j < i + 3; ++j)
            {
                value = value << 8;

                if (j < bytes.Length)
                {
                    value |= bytes[j];
                }
                else
                {
                    paddingCount++;
                }
            }

            //Masking
            //1111 1100 0000 0000 0000 0000 (0x3F << 6 << 6 << 6)
            //0000 0011 1111 0000 0000 0000 (0x3F << 6 << 6)
            //0000 0000 0000 1111 1100 0000 (0x3F << 6)
            //0000 0000 0000 0000 0011 1111 (0x3F)
            int masking = 0x3F << 6 << 6 << 6;

            //3byte를 6bit로 쪼개기 (없다면 패딩처리 '=')
            for (int j = 0; j < 4; ++j)
            {
                if (paddingCount > 3 - j)
                {
                    sb.Append("=");
                }
                else
                {
                    int v = (value & masking) >> 6 * (3 - j);
                    sb.Append(table[v]);
                }

                masking = masking >> 6;
            }
        }

        return sb.ToString();
    }

    private static byte[] Base64Decoding(string text)
    {
        List<byte> byteList = new List<byte>();

        for (int i = 0; i < text.Length; i += 4)
        {
            int value = 0;
            int paddingCount = 0;

            for (int j = i; j < i + 4; ++j)
            {
                value = value << 6;

                if (text[j] != '=')
                {
                    value |= table.IndexOf(text[j]);
                }
                else
                {
                    paddingCount++;
                }
            }

            int masking = 0xFF << 8 << 8;

            for (int j = 0; j < 3; ++j)
            {
                if (paddingCount > (2 - j))
                {
                    break;
                }
                else
                {
                    int v = (value & masking) >> 8 * (2 - j);
                    byteList.Add((byte)v);
                }

                masking = masking >> 8;
            }

            //Console.WriteLine("Processing... " + Encoding.UTF8.GetString(byteList.ToArray()));
        }

        return byteList.ToArray();
    }
}

 

C#, Java 간 암복호화를 사용할 일이 있어서 정리해봅니다.

처리 방법은 2가지가 있습니다.

1. TransformFinalBlock : 바이트 전체를 한번에 처리

2. CryptoStream : 스트림 단위로 잘라서 처리 1MB 이상이면 권장된다고 합니다!

using System;
using System.Security.Cryptography;
using System.Text;

namespace ConsoleApp1
{
    class Program
    {
        private static readonly string KEY = "0123456789abcdef0123456789abcdef"; // 32-byte
        private static readonly string IV = "abcdef9876543210"; // 16-byte

        private static Aes aes;

        static void Main(string[] args)
        {
            aes = Aes.Create();
            aes.Key = Encoding.UTF8.GetBytes(KEY); //CBC므로 32바이트
            aes.IV = Encoding.UTF8.GetBytes(IV); //16바이트 (첫 XOR 값)
            aes.Mode = CipherMode.CBC; //16바이트 단위로 XOR 처리
            aes.Padding = PaddingMode.PKCS7; //패딩 끝 부분 바이트 처리 (부족한 길이 반복)

            string originalText = "Hello, AES-256!";
            Console.WriteLine("Original: " + originalText);

            string encryptedText = Encrypt(originalText);
            Console.WriteLine("Encrypted: " + encryptedText);

            string decryptedText = Decrypt(encryptedText);
            Console.WriteLine("Decrypted: " + decryptedText);
        }

        static string Encrypt(string plainText)
        {
            ICryptoTransform encryptor = aes.CreateEncryptor();
            byte[] inputBytes = Encoding.UTF8.GetBytes(plainText);

            //****************************************************************
            //통 Block 방식
            byte[] encryptedBytes = encryptor.TransformFinalBlock(inputBytes, 0, inputBytes.Length);
            return Convert.ToBase64String(encryptedBytes); //통신용이라면 base64가 안전 (아니면 그냥 UTF8로 해도 괜찮습니다!)
            
            //****************************************************************
            //Stream 방식 (1MB 이상이면 스트림 방식 권장)
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
                {
                    cs.Write(inputBytes, 0, inputBytes.Length);
                    cs.FlushFinalBlock();
                }
                return Convert.ToBase64String(ms.ToArray());
            }
        }

        static string Decrypt(string encryptedText)
        {
            ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
            byte[] encryptedBytes = Convert.FromBase64String(encryptedText); //Encrypt 후반에 base64를 썻는지에 따라 처리!
            
            //****************************************************************
            //통 Block 방식
            byte[] decryptedBytes = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
            return Encoding.UTF8.GetString(decryptedBytes);
            //****************************************************************

            //Stream 방식 (1MB 이상이면 스트림 방식 권장)
            using (MemoryStream ms = new MemoryStream(encryptedBytes))
            {
                using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
                {
                    using (MemoryStream result = new MemoryStream())
                    {
                        cs.CopyTo(result);
                        return Encoding.UTF8.GetString(result.ToArray());
                    }
                }
            }
        }
    }
}

 

 

 

C#가 호환되는 자바쪽 소스 (GPT가 알려준 소스..!)

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class Test {
    // 주어진 AES 256-bit (32-byte) Key와 16-byte IV
    private static final String KEY = "0123456789abcdef0123456789abcdef"; // 32-byte
    private static final String IV = "abcdef9876543210"; // 16-byte

    public static String encrypt(String plainText) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec secretKey = new SecretKeySpec(KEY.getBytes(), "AES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(IV.getBytes());

        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
        byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));

        return Base64.getEncoder().encodeToString(encrypted);
    }

    public static String decrypt(String encryptedText) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec secretKey = new SecretKeySpec(KEY.getBytes(), "AES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(IV.getBytes());

        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
        byte[] decodedBytes = Base64.getDecoder().decode(encryptedText);
        byte[] decrypted = cipher.doFinal(decodedBytes);

        return new String(decrypted, "UTF-8");
    }

    public static void main(String[] args) {
        try {
            String originalText = "Hello, AES-256!";
            System.out.println("Original: " + originalText);

            String encryptedText = encrypt(originalText);
            System.out.println("Encrypted: " + encryptedText);

            String decryptedText = decrypt(encryptedText);
            System.out.println("Decrypted: " + decryptedText);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Process.Start 혹은 Process 클래스를 구현하여 사용하여 프로그램 실행이 가능합니다.

아래는 엑셀, 텍스트 문서를 열은 예제입니다.

using System;
using System.Diagnostics;
using System.IO;

namespace ConsoleApp
{    
    class Program
    {
        public static void Main(string[] args)
        { 
            Process process = new Process();

            /* 프로그램 실행 시키고 기다리기.
            Process pro = Process.Start("...");
            pro.WaitForExit();
            */

            Console.WriteLine("[Excel] 프로세스 시작!");

            process.StartInfo.Arguments = Path.Combine(Directory.GetCurrentDirectory(), "test.xlsx");
            process.StartInfo.FileName = "excel.exe";
            process.StartInfo.UseShellExecute = true; //엑셀 실행 시 UseShellExecute 필요!

            process.Start();
            process.WaitForExit();

            //위와 동일한 작업을 합니다!
            //Process pro = Process.Start(new ProcessStartInfo("excel.exe", Path.Combine(Directory.GetCurrentDirectory(), "test.xlsx")) { UseShellExecute = true });
            //pro.WaitForExit();

            Console.WriteLine("[Excel] 프로세스 종료!");

            Console.WriteLine("[notepad] 프로세스 시작!");

            process.StartInfo.Arguments = Path.Combine(Directory.GetCurrentDirectory(), "test.txt");
            process.StartInfo.FileName = "notepad.exe";

            process.Start();
            process.WaitForExit();

            Console.WriteLine("[notepad] 프로세스 종료!");
        }
    }
}

 

결과! (해당 경로에 파일이 있어야 열립니다)

 

업무 중 필요해서 만들어 본 금액을 한글로 표시해주는 코드입니다.

만들 때 마다 코드가 달라지는데 기본적인 방식은 비슷하기에 저장..

 

using System;

namespace ConsoleApp2
{
	class Program
	{
		private static readonly string[] num = { "", "일", "이", "삼", "사", "오", "육", "칠", "팔", "구" };
		private static readonly string[] digit = { "", "십", "백", "천" };
		private static readonly string[] word = { "", "만 ", "억 ", "조 ", "경 " }; //띄어쓰기 포함시켰습니다.

		//숫자 -> 한글 값
		public static void Main(string[] args)
		{
			string result = string.Empty;
			string sign = string.Empty;
			string readLine = Console.ReadLine();

			int wordIndex = 0;
			long input = 0;

			if (readLine[0] == '-') //음수 양수 확인
			{
				sign = "-";
			}

			//숫자만 추출 (그냥 만들어본거 ㅋ)
			for (int i = 0; i < readLine.Length; ++i)
			{
				if ('0' <= readLine[i] && readLine[i] <= '9')
				{
					input = input * 10 + readLine[i] - '0';
				}
			}

			while (input > 0)
			{
				string subResult = "";

				for (int i = 0; i < 4; ++i) // 1, 10, 100, 1000 단위별로 확인합니다.
				{
					long val = input % 10;
					input /= 10;

					if (val == 0) //0은 출력하지 않습니다.
					{
						continue;
					}

					if (val == 1 && i != 0) //일천, 일백, 일십에서는 일을 제거해줍니다.
					{
						subResult = digit[i] + subResult;
					}
					else //나머지 숫자들에 대해선 정상 출력해줍니다.
					{
						subResult = num[val] + digit[i] + subResult;
					}
				}

				if (subResult != "") //값이 있다면 추가해줍니다.
				{
					result = subResult + word[wordIndex] + result;
				}

				wordIndex++;
			}

			if (string.IsNullOrEmpty(result))
			{
				Console.WriteLine("영원");
			}
			else
			{
				Console.WriteLine("{0}{1}원", sign, result);
			}
		}
	}
}

C#은 기본적으로 StructLayout 가 정해져 있습니다.

클래스는 [StructLayout(LayoutKind.Auto, Pack = 0)]

구조체는 [StructLayout(LayoutKind.Sequential, Pack =0)]

 

평소엔 신경쓰지 않아도 되지만 C, C++ 혹은 서버와 통신 등 메모리를 맞춰줘야 될 때

사용되는 기능이니 이런 것이 있다는 것만 알면 될거 같습니다.

아래 코드는 C#으로 C, C++ 포인터를 흉내내어 메모리 참조를 해본 코드입니다.

 

using System;
using System.Runtime.InteropServices; // [StructLayout ] 선언에 필요합니다.

//참고 설명 https://www.csharpstudy.com/DevNote/Article/10

//*****************************************************************
//
//  기본값
//  class  : [StructLayout(LayoutKind.Auto, Pack = 0)]
//  struct : [StrcutLayout(LayoutKind.Sequential, Pack = 0)]
//
//  Pack : 0이면 자동 세팅에 따릅니다. (0, 1, 2, 4, 8, 16... 128 까지 2의 배수만 가능합니다.)
//         1 이상이면 Pack과 타입 크기 중 가장 큰 단위에 따라 패딩을 넣어줍니다.
//      
//  ex)
//      [StructLayout(LayoutKind.Sequential, Pack = 0)]
//      struct MyStruct
//      {
//          public int i;     // 4
//          public double d;  // 8
//          public byte b;    // 1
//      }
//
//      가장 큰 사이즈에 맞추어 크기가 조절 됩니다.
//      Pack = 0 이면 가장 큰 사이즈 byte
//      sizeof(MyStruct) == 24
//      
//      i  = (0~3)
//    패딩 = (4~7)
//      d  = (8~15)
//      b  = (16)
//    패딩 = (17~23)
//
//      Pack = 1 이면 1에 가까운 타입에 맞추어집니다. 즉 byte 중심이 되며
//      i = (0~3), d = (4~11), b = (12) 가 되어 0~12까지 size = 13이 됩니다.
//
// LayoutKind.Sequential    : 메모리상에 순차적으로 저장합니다.
//            Auto          : 힙 영역에 자동으로 저장합니다.
//            Explicit      : 직접 메모리 영역을 지정해줍니다.
//                            변수에 [FieldOffset()] 식으로 지정해주어야 합니다.
//
//****************************************************************


namespace StructLayout
{
    class Program
    {
        [StructLayout(LayoutKind.Explicit, Pack = 1)] //int형 4에 맞춰집니다.
        public struct Test
        {
            [FieldOffset(0)]
            public int value; // 4 (0000 0000, 0000 0000, 0000 0000, 0000 0000)

            [FieldOffset(0)]
            public byte value1; // (0000 0000 ____ ____ ____ ____ ____ ____)

            [FieldOffset(1)]
            public byte value2; // (____ ____ 0000 0000 ____ ____ ____ ____)

            [FieldOffset(2)]
            public byte value3; // (____ ____ ____ ____ 0000 0000 ____ ____)

            [FieldOffset(3)]
            public byte value4; // (____ ____ ____ ____ ____ ____ 0000 0000)
        }

        //c언어의 포인터를 흉내낼 수 있습니다!
        static unsafe void Main(string[] args) //unsafe : 포인터 사용지 설정이 필요합니다.
        {
            Test test = new Test();

            Console.WriteLine("sizeof(TEST) : {0}", sizeof(Test));

            //c, c++언어의 포인터
            int* startAddress = (int*)&test;

            //1100 1100, 0000 0100, 0000 0001, 0000 0001
            test.value = (1 << 31) | (1 << 30) | (1 << 28) | (1 << 27) | //1100 1100 ____ ____ ____ ____ ____ ____
                         (1 << 18) |                                     //1100 1100 0000 0100 ____ ____ ____ ____
                         (1 << 8)  |                                     //1100 1100 0000 0100 0000 0001 ____ ____
                         1;                                              //1100 1100 0000 0100 0000 0001 0000 0001

            Console.WriteLine("test.value : {0}", Convert.ToString(test.value, 2)); //2진수로 출력
            Console.WriteLine("test.value1 : {0}", Convert.ToString(test.value1, 2)); //2진수로 출력 0000 0001
            Console.WriteLine("test.value3 : {0}", Convert.ToString(test.value2, 2)); //2진수로 출력 0000 0001
            Console.WriteLine("test.value2 : {0}", Convert.ToString(test.value3, 2)); //2진수로 출력 0000 0100
            Console.WriteLine("test.value4 : {0}", Convert.ToString(test.value4, 2)); //2진수로 출력 1100 1100
        }
    }
}

 

 

결과 값 2진수로 표현하였고 앞의 0은 사라집니다.

 

참고할거라서 먼저 코드부터 올리겠습니다 ' - '!  (설명은 밑에 간단히)

 

(+ 빈 값을 자동으로 제거해주는 방법도 있습니다

JsonConvert.SerializeObject(data,  //데이터
                            Formatting.Indented, //줄 바꿈 여부
                            new JsonSerializerSettings
                            {
                              DefaultValueHandling = DefaultvalueHandling.Ignore, //기본 값 제거
                              NullValueHandling = NullValueHandling.Ignore //NULL 값 제거
                            };

/*
Formatting.None  : 줄 바꿈 없음 
ex) { "a"="asd"}

Formatting.Indented : 줄 바꿈
ex)
{
  "a" = "asd"
}

DefaultvalueHandling.Ignore : 문자 = null, 숫자 = 0 제거
NullValueHandling.Ignore    : 문자 or 숫자 = null 제거

*/

 

예제 코드

using System;
using System.Collections.Generic;
using Newtonsoft.Json;                  //JsonProperty, JsonConvert
using Newtonsoft.Json.Linq;             //JObject, JArray
using Newtonsoft.Json.Serialization;    //Serialize, Deserialize

namespace ConsoleApp2
{
    class Program
    {
        class TestClass
        {
            //이름이 동일한 곳으로 파싱됩니다.
            //[JsonProperty("a")] 
            public int a;

            //제이슨에서 xx변수를 b라고 호칭합니다.
            [JsonProperty("b")]
            public int xx;

            //리스트(배열) 가능!
            public List<string> c = new List<string>();
        }

        static void Main(string[] args)
        {
            //*********************직렬화*************************

            TestClass test = new TestClass();
            test.a = 1;
            test.xx = 2;
            test.c.Add("hi");
            test.c.Add("ok");

            string serialized = JsonConvert.SerializeObject(test);
            string message = "{\"a\":1,\"b\":2,\"c\":[\"hi\",\"ok\"]}";
            
            //xx가 JsonProperty에 의해 c로 변환 됩니다.
            Console.WriteLine("serialized : {0}", serialized);
            Console.WriteLine("message : {0}", message);

            //*****************  파싱/ 역직렬화 ********************

            //오브젝트 형태로 파싱하여 사용하기
            JObject jObject = JObject.Parse(serialized);
            JArray jArray = jObject["c"].ToObject<JArray>(); //JArray로 변환

            Console.WriteLine("JObject : {0} {1}", jObject["a"], jObject["b"]);
            Console.WriteLine("JArray : {0} {1}", jArray[0], jArray[1]);

            //역직렬화 후 사용하기
            TestClass testClass = JsonConvert.DeserializeObject<TestClass>(message);
            Console.WriteLine("JsonConvert.DeserializeObject a:{0} b:{1}", testClass.a, testClass.xx);
            Console.WriteLine("JsonConvert.DeserializeObject c[0]:{0} c[1]:{1}", testClass.c[0], testClass.c[1]);

            //역직렬화 후 사용하기 (중간에 값이 빠져도 역직렬화 가능합니다!)
            string message2 = "{ b:1 }";
            TestClass testClass2 = JsonConvert.DeserializeObject<TestClass>(message2);
            Console.WriteLine("JsonConvert.DeserializeObject a:{0} b:{1}", testClass2.a, testClass2.xx);
        }
    }
}

직렬화 / 파싱 / 역직렬화 결과

 

JSON : Java Script Object Notation    키와 값을 갖는 문자열 형태입니다.

ex)  { name : "이름" , age : "33" } 

 

웹상에서 데이터를 주고 받기 편하고 많이 사용합니다!

위의 코드에 기본적인 사용법은 적혀 있으니 참고하시기 바랍니다.

 

JObject 형태로 사용하거나 class로 직렬화/역직렬화 가능합니다.

 

클래스 없이도 JProperty 형태로 삽입 만들 수도 있답니다. (아니면 위의 message처럼 직접 써도 되구요~)

JObject obj = new JObject();
obj.Add(new JProperty("oo", "!!"));
Console.WriteLine(obj["oo"]); // !!

 

 

설치법

1. 비주얼스튜디오 "솔루션 NuGet 패키지 관리" 에서 다운 받을 수 있습니다.

2. Json 홈페이지에서 .dll 다운도 가능합니다.

 

 도구 -> NuGet 패키지 관리자 -> 솔루션용 NuGet 패키지 관리

 

찾아보기 -> Json 검색 -> 오른쪽에서 설치 -> 솔루션 탐색기 참조에 생성됩니다.

using Newtonsoft.Json을 사용 가능해집니다!

 

using System;
using System.Net; //IPAddress, Dns
using System.Net.Sockets; //AddressFamily

namespace ConsoleServerTest
{
    class Program
    {
        public static void Main (string[] args)
        {
            PrintMyAddress();
        }

        private static void PrintMyAddress()
        {
            IPAddress[] host = Dns.GetHostAddresses(Dns.GetHostName());

            for (int i = 0; i < host.Length; ++i)
            {
                if (host[i].AddressFamily == AddressFamily.InterNetworkV6) //IPv6
                {
                    Console.WriteLine("IPv6 주소 [{0}]", host[i]);
                }

                if (host[i].AddressFamily == AddressFamily.InterNetwork) //IPv4
                {
                    Console.WriteLine("IPv4 주소 [{0}]", host[i]);
                }
            }
        }
    }
}

실행 결과

IP 주소는 고정 아이피를 신청하지 않는 이상 계속 바뀌게 됩니다.

다른 기기 (공유기, 스위칭 허브 등) 연결 없이 바로 연결했기 때문에

바로 제가 쓰고 있는 유동 아이피가 나온 모습입니다 ㅎㅎ

+ Recent posts