Partial

클래스, 구조체, 인터페이스 등의 선언에 사용된다.

partial 제한자로 선언된 클래스, 구조체, 인터페이스 등은 여러 파일에 나누어 작성할 수 있다.

 

public class Person
{
	public string FirstName { get; set; }
    public string LastName { get; set; }
    
    public void SayHello()
    {
    	Console.WriteLine($"Hello, my name is {FirstName} {LastName}.");
    }
}

Person이라는 클래스가 하나의 파일에 선언되고 작성되어 있다. 이 클래스를 여러 파일로 나누어 선언하기 위해 partial 키워드를 사용하면 다음과 같이 사용할 수 있다.

 

// Person.cs
public partial class Person
{
	public string FirstName { get; set; }
    public string LastName { get; set; }
}

// Person_SayHello.cs
public partial class Person
{
	public void SayHello()
    {
    	Console.WriteLine($"Hello, my name is {FirstName} {LastName}.");
    }
}

 

Person.cs 파일과 Person_SayHello.cs 파일은 같은 네임스페이스 안에 있으며 partial 키워드를 사용해 클래스를 선언하였기 때문에 다른 파일에서 Person 클래스를 동일하게 partial 키워드를 사용해 선언하면 이 클래스는 하나의 클래스로 인식된다. partial로 선언된 클래스는 컴파일 시점에 자동으로 하나의 클래스로 합쳐지기 때문에 별도의 참조가 필요하지 않다.

 

이러한 기능은 특히 협업에서 용이하게 사용이 가능하다.

큰 규모의 코드를 개발하기 위해서 여러 개발자가 협업을 하게 된다면 동시에 하나의 클래스나 구조체를 작성하는 상황이 있다. 이런 상황에서 partial 키워드를 사용하여 하나의 클래스를 여러 파일에 나누어 각자 작성할 수 있고 이렇게 하면 동시에 작성을 각자가 코드를 작성하더라도 서로 영향을 주지 않고 작업을 진행할 수 있다.

 

양이 많은 코드의 경우 하나의 파일에 모두 작성하게 되면 보기나 수정이 힘들어진다. 이때 partial 키워드를 사용하면 코드를 작은 단위로 분할하여 작성할 수 있기 때문에 코드 가독성도 좋아지고 유지보수도 편리해진다. 

728x90
반응형

new

Instance

객체를 생성할때 사용한다.

C#에서는 내장 클래스인 string, int, double 등을 포함한 모든 클래스 object를 상속받기 때문에  new 키워드를 사용해서 객체를 생성할 수 있다. 

int n = new int();
string s = new string();
MyStruct structInstance = new MyStruct();
MyClass classInstance = new MyClass();

하지만 내장 클래스들은 구조체로 정의되어 있기 때문에 구조체 변수를 생성할 때 new를 사용하지 않고 객체를 바로 생성할 수 있다.

int n = 0;
float f = 1.0f;

string의 경우 .Net에서 특별히 내부적으로 string literal로 정의되어 있는데 때문에 일반적인 참조 타입과는 다르게 직접 변수를 할당하여 객체가 생성이 가능하다.  

 

* string literal : 문자열 상수는 소스 코드 상에 고정된 문자열 값이다.

 

Inherit

new 키워드는 상속과 관련해서도 사용이된다.

상속 관계에 있는 클래스에서 메서드, 프로퍼티, 이벤트 등의 멤버를 재정의할 때 사용되는데 일반적으로 멤버의 재정의에는 override 키워드를 사용하지만 new키워드를 통해서도 멤버의 재정의가 가능하다.

 

class BaseClass
{
	public void Print()
    {
    	Console.WriteLine("Base class");
    }
}

class DerivedClass : BaseClass
{
	public new void Print()
    {
    	Console.WriteLine("Derived class");
    }
}

여기서 new 키워드를 사용하여 재정의된 메서드는 부모 클래스에서 정의된 멤버와 자식 클래스에서 정의된 멤버가 모두 유지되는데 이는 덮어쓰는 override와 다르게 두 개의 멤버가 서로 다른 것으로 재정의된 메서드는 부모 클래스의 멤버와는 관계가 없는 새로운 멤버로 취급된다.

DerivedClass obj = new DerivedClass();
obj.Print();
// "Derived class" 출력

BaseClass obj = new DerivedClass();
obj.Print();
// "Base class" 출력

 

 

728x90
반응형

extern

'외부의'라는 뜻을 가지는 External의 약자로 외부에 선언된 함수 또는 객체임을 명시하는 역할을 한다.

이때 외부란 C# 코드 이외의 언어로 작성된 코드를 뜻하며 DLL이나 C/C++ 등으로 작성된 함수를 말한다.

이런 외부에서 작성된 코드 즉, C# 및. Net 프레임 워크에서 사용되지 않는 코드 다시 말해서 CLR에서 관리되지 않는 코드를 unmanaged code라고 하는데 이러한 unmanaged code를 불러오기 위해서는 interop 기술이 필요하다.

 

Interop 정리글

 

간략하게 Interop은 다른 언어나 플랫폼에서 작성된 코드를 호출하거나 받는 기술로 COM, P/Invoke, C++/CLI 등이 대표적으로 있는데 extern 키워드는 이러한 함수나 객체가 외부의 것임을 나타내는 역할을 한다.

 

일반적으로 C#에서 많이 사용하는 P/Invoke 방식은 DllImport arttribute와 함께 사용한다.

이 경우 메서드는 반드시 static으로 선언되어야 한다.

// Microsoft AVI File support library
[DllImport("avifil32.dll")] // Interop, P/Invoke
private static extern void AVIFileInit();

 

extern alias

.Net 어셈블리에서 다른 버전의 동일한 어셈블리의 참조가 필요한 경우에 사용할 수 있다.

일반적으로 .Net 프로젝트에서 어셈블리의 참조는 using이나 Imports를 사용하여 참조하는데 만약 서로 다른 버전의 어셈블리를 참조하는 경우에는 컴파일러가 어떤 버전을 사용해야 하는지 구분이 필요하기 때문에 이런 경우 extern alias 키워드를 사용한다.

 

동일한 어셈블리를 버전별로 참조하기 위해서는 각각의 어셈블리를 특정시킬 수 있도록 만드는 작업이 필요하다.

특정시키는 방법으로는 각 어셈블리의 별칭을 지정하는 방법과 이름을 변경하는 방법이 있다.

 

Alias

어셈블리의 별칭을 지정하는 방법은 대표적으로 두 가지 방법이 있다.

 

1. Visual Studio 

비주얼 스튜디오의 솔루션 탐색기에서 별칭을 수정할 수 있다.

Assembly > 우클릭 속성 > Aliases 수정

2. 프롬프트 창

프롬프트에서 어셈블리에 별칭을 부여할 수 있다.

/r:GridV1=grid.dll
/r:GridV2=grid20.dll

 

각각의 어셈블리에 외부에서 사용할 별칭 GridV1과 GridV2가 지정된다.

 

이렇게 별칭을 지정해 주면 extern 키워드를 사용하여 별칭을 참조하면 동일한 어셈블리를 구분해서 참조가 가능해진다.

extern alias GridV1;
extern alias GridV2;
// can using namespace
using Class1V1 = GridV1::Namespace.Class1;
using Class1V2 = GridV2::Namespace.Class1;

 

Name

별칭을 지정하지 않고 이름을 변경하는 방법으로도 참조가 가능하다.

비주얼 스튜디오에서 별칭을 수정했던 설정창을 다시 켜보면 상단에 이름 속성을 확인할 수 있다.

이름을 사용하기 위해서는 별칭이 지정되지 않아야 하므로 별칭을 지우고 이름을 수정한다.

 

그 후에 C#에서 Type.GetType 메서드를 사용하면 어셈블리에서 Type을 가져올 수 있는데 이때 어셈블리의 전체 이름을 사용하여 Type을 가져오면 해당 어셈블리를 특정해서 참조할 수 있게 된다.

Type myType = Type.GetType("MyNamespace.MyType, MyAssembly");

 

728x90
반응형

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

Interoperability  (0) 2023.02.02
Managed, Unmanaged, Native Code  (0) 2023.02.02
C# 키워드 : delegate, event, action  (0) 2023.01.31
C# 상수 키워드 : const  (0) 2023.01.31
C# 비동기화 키워드 : async, await  (0) 2023.01.31

const

상수라는 뜻을가지는 Constant에서 따온 키워드이다.

상수란 프로그래밍에서 변하지 않는 값을 의미하는데 한번 값이 정해지면 프로그램이 실행되는 동안 그 값은  항상 일정하다. 컴파일 타임에 값이 결정되므로 런타임 시 메모리를 사용하지 않게 되어 상수를 사용하면 메모리 사용을 줄일 수 있다.

 

public class Program
{
	public static void Main(string[] args)
    {
    	const int A = 10;
        A = 10; // Compiler Error CS0131
    }
}

 

const 키워드로 선언된 변수는 상수로 취급되기 때문에 값을 재할당하면 컴파일 에러가 뜬다. 따라서 상수는 코드 흐름에서도 바뀔 필요가 없고 일정하게 사용될 값이 필요할 때 사용한다.

 

literal const

리터럴 상수 또한 상수와 마찬가지로 변하지 않는 값을 표현할 때 사 용는데 두 개념에는 약간의 차이가 있다.

상수는 const 예약어를 사용해서 변수형태로 선언되고 컴파일 시간에 값이 결정되어 프로그램 중에 값이 변경되지 않는 것이라면 리터럴 상수는 컴파일러가 코드에서 직접 사용할 수 있는 값을 의미한다. 예를 들어서 0, 1, 2, 3 등이 모두 정수형 리터럴 상수로 변수나 상수가 아니면서 프로그램 실행 중에도 변경할 수 없는 값이다.

 

// 상수 PI
const double PI = 3.14159265358979;
// 숫자 리터럴 상수
double radius = 3.0;
// 문자 리터럴 상수
char c = 'C';
// 문자열 리터럴 상수
string str = "Str";

리터럴 상수에는 숫자뿐만 아니라 문자 또한 포함된다.

즉 코드 상에서 선언되지 않았으면서 변수에 할당이 가능한 모든 값을 리터럴 상수라고 할 수 있다.

728x90
반응형

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

C# 외부 코드 사용 키워드 : extern  (1) 2023.01.31
C# 키워드 : delegate, event, action  (0) 2023.01.31
C# 비동기화 키워드 : async, await  (0) 2023.01.31
C# 클래스 추상화 키워드 : abstract  (0) 2023.01.25
Main method  (0) 2023.01.19

async

메서드, 람다 표현식 또는 무명 메서드를 비동기로 특정할 수 있다.

메서드나 표현식에 async 제한자가 붙으면 비동기식 메서드라고 한다.

 

public async Task<T> ExampleMethodAsync()
{
	string contents = await NetworkManager.GetData(url);
}

 

async만 사용한다고 메서드가 비동기로 작동하는 것은 아니며 첫 번째 await 표현식을 만날 때까지 동기적으로 실행된다. 

await의 동작이 완료될 때까지 메서드는 대기하게 되고 메서드 호출자는 다음 동작을 진행하게 된다.

 

async 키워드로 선언된 비동기 메서드가 await 표현식이나 구문이 포함되어있지 않으면 컴파일러는 경고를 띄우게 된다.

비동기 메서드의 반환형은 Task <T>, Task(void) 형태로 정의되고 return T와 같이 해당 타입만 반환한다.

컴파일러는 return T을 자동으로 Task <T>로 변환한다. 특히 async 메서드는 이벤트핸들러를 위해 void의 반환을 허용하고 있다.

 

awiat은 일반적으로 Task 또는 Task <T> 객체와 함께 사용되는데 Task 이외에 awaitable 클래스도 함께 사용할 수 있다.

* awaitable : GetAwaiter() 메서드를 갖는 클래스

 

 

About sync and async

 

Example

    class Program
    {
        public static void Main(string[] args)
        {
            TaskTest(10);
            Console.WriteLine("============Call Main============");

            Console.ReadLine();
        }
        private static async void TaskTest(int count)
        {
            Console.WriteLine("============Call Task1============");

            for (int i = 0; i < count; i++)
            {
                var message = String.Format("Count {0}", i);
                Console.WriteLine(message);
                await Task.Delay(1000);
            }

            Console.WriteLine("============End Task1============");
        }
    }

Main 함수가 실행되면서 TaskTest를 호출한다.

그리고 곧이어 비동기적으로 Main 함수의 다음 코드가 실행되면서 TaskTest의 다음 동작이 진행된다.

 

 메인함수 또한 비동기로 정의하여 사용할 수 있다.

    class Program
    {
        public static async Task Main(string[] args)
        {
            await TaskTest(10);
        }
        private static async Task TaskTest(int count)
        {
            Console.WriteLine("============Call Task1============");

            for (int i = 0; i < count; i++)
            {
                var message = String.Format("Count {0}", i);
                Console.WriteLine(message);
                await Task.Delay(1000);
            }

            Console.WriteLine("============End Task1============");
        }
    }

메인함수는 await 기준으로 비동기적으로 작업이 처리된다.

 

요약

async 메서드 내부에서 await을 만날게 되면 다음과 같은 경우의 수 가 있다.

1. awaitable이 예외를 발생시킨다면 await은 throw exception 한다.

2. awaitable이 이미 종료됐다면 메서드는 일반 메서드와 같이 동기적으로 실행된다.

3. awaitable이 종료된 상태가 아니라면 종료될 때 await 다음 코드가 실행되도록 대기 큐에 등록하고 async 메서드의 호출자에게 Task를 반환한다.

 

microsoft document 비동기 프로그래밍 예제

https://learn.microsoft.com/ko-kr/dotnet/csharp/programming-guide/concepts/async/#final-version

 

C#의 비동기 프로그래밍

async, await 및 Task를 사용하여 비동기 프로그래밍을 지원하는 C# 언어에 대해 간략히 설명합니다.

learn.microsoft.com

 

 

728x90
반응형

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

C# 키워드 : delegate, event, action  (0) 2023.01.31
C# 상수 키워드 : const  (0) 2023.01.31
C# 클래스 추상화 키워드 : abstract  (0) 2023.01.25
Main method  (0) 2023.01.19
테스트 환경  (0) 2023.01.17

abstract

추상적인

구현이 완전하지 않은 상태임을 타나내는 키워드이다.

클래스, 메서드, 프로퍼티, 인덱서, 이벤트와 함게 사용될 수 있다. 

일반적으로 추상 클래스를 구현하는데 사용되며 자체적으로는 인스턴스화 되지 않고 파생된 비추상 클래스에 의해 구현되어 사용된다. 

 

    abstract class Person
    {
        public abstract int GetInfo();
    }

    class Joon : Person
    {
        private int m_age;
        public Joon(int age) => m_age = age;
        public override int GetInfo() => m_age;
    }

    public class Program
    {
        static void Main(string[] args)
        {
            // Error, cannot create an instance of the abstract type.
            Person person = new Person(); 

            Joon joon = new Joon(30);
            Console.WriteLine(joon.GetInfo());
        }
    }

Feature

- 추상 클래스는 인스턴스화할수없다.

- 추상 클래스는 추상 메서드와 접근자를 포함할 수 있다.

- abstract 제한자는 sealed 제한자와 반대의미이므로 같이 사용할 수 없다.

  (abstract : 상속을 필요로하는 제한자, sealed : 상속을 방지하기위한 제한자)

- 추상 클래스로부터 파생된 클래스는 반드시 추상 메서드와 접근자의 구현이 필요하다.

 

메서드와 프로퍼티의 선언에서 abstract 제한자의 사용은 구현을 포함하지 않는것을 나타낸다.

- 추상 메서드는 암묵적으로 가상 메서드이다.

- 추상 메서드는 오직 추상 클래스 내에서만 선언이 허용된다.

- 추상 메서드는 구현이 없어야하므로 선언시 중괄호가 필요하지 않다.

 

Derived abstract class

추상 클래스를 파생 클래스로 만들어 특정 가상 메서드의 상속하여 추상 메서드로 가상 메서드를 재정의할 수 있다.

    public class BaseClass
    {
        public virtual void VirtualMethod(int i) { }
    }

    public abstract class AbstractClass : BaseClass
    {
        public abstract override void VirtualMethod(int i);
    }

	//DerivedClass.ViertualMethod는 BaseClass.VirtualMethod에 접근할 수 없다.
    public class DerivedClass : AbstractClass
    {
        public override void VirtualMethod(int i)
        {
            throw new NotImplementedException();
        }
    }

추상 클래스로부터 파생된 클래스는 메서드의 원래 구현에 접근할 수 없다. 

이러한 방식으로 추상 클래스는 파생 클래스로부터 가상 메서드의 구현을 강제할 수 있다.

728x90
반응형

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

C# 상수 키워드 : const  (0) 2023.01.31
C# 비동기화 키워드 : async, await  (0) 2023.01.31
Main method  (0) 2023.01.19
테스트 환경  (0) 2023.01.17
.Net Framework  (0) 2023.01.17

예약어

예약어는 식별자로 사용할 수 없는 문자를 뜻한다.

현재 또는 향후 사용될 문자까지 예약어로 등록되기도 한다.

*식별자(identifier)

변수, 함수, 클래스 등의 이름을 지정하는데 사용되는 문자열

 

키워드

컴파일러에게 특별한 의미를 가지고 있는 문자이다. 

키워드가 가지는 특징은 언어마다 다른데 키워드를 식별자로 사용할 수 있는 경우도 있고 그렇지 않은 경우도 있다.

 

두 개념을 명확하게 구분짓는게 애매하다. 

어떤 언어에서는 모든 키워드가 예약어로 되어있어 키워드를 식별자로 사용하는게 불가능하지만 또 일부 언어에서는 키워드를 식별자로 사용하기도 하기 때문에 키워드를 예약어로 단정할 수 없고 예약어 또한 현재 사용중이 아닌 문자도 사용을 못하게 하는 경우가 있기 때문에 모든 예약어가 키워드처럼 의미를 가지고 있지 않을 수 있다.

 

그래서 예약어는 식별자로 사용 못하는 문자 키워드는 특별한 의미를 가지고 있는 문자로 구분하고 각 언어마다 키워드와 예약어를 파악하는게 중요하는게 좋을것같다.

 

💡키워드를 식별자로 사용하는 예 : Fortan ( if then then then = else else else = then)

💡예약어가 키워드로 사용되지 않는 예 : Java  (goto)

 

키워드 종류

키워드는 사용되는 방식과 기능 그리고 문맥에 따라서 종류가 나누어지며 언어마다 각기 다른 특징을 가지고 있기도 하지만 공통되는 부분도 많다.

 

일반적으로 사용되는 키워드를 정리한다.

 

제한자(Modifier)

타입과 멤버를 누가 수정할 수 있는지 특정하여 나타내는 키워드이다. 프로그램의 특정한 부분이 다른 곳에서 수정되는것을 허용하거나 방지하도록한다.

 

접근 제한자(Access Modifier)

클래스, 메서드, 프로퍼티, 필드 등의 멤버를 선언할 때 적용되는 것으로 클래스간의 멤버 접근성을 정의한다.

 

구문(Statement)

구문은 프로그램의 흐름과 연관된 키워드이다.

대표적으로 if, for 등의 키워드가 있다.

 

메서드 매개변수(Method Parameter)

메서드의 매개변수에서만 적용되는 키워드이다.

 

네임스페이스 키워드(Namespace Keywords)

네임스페이스 및 관련 연산자에 적용되는 키워드이다.

using ... 

 

연산자 키워드(Operator Keywords)

기타 작업을 수행하는 키워드이다.

sizeof ...

 

접근 키워드(Access keywords)

객체 또는 클래스에 접근하는데 사용된다.

this ...

 

리터럴 키워드(Literal Keywords)

특정 값으로 평가될 수 있는 키워드이다.

null, false, true 등

 

타입 키워드(Type Keywords)

자료형에 사용되는 키워드이다.

int, char, float ...

 

문맥상 키워드(Contextual Keywords)

특정 문맥상에서만 키워드로 취급된다.

 

 

728x90
반응형

'Program Language' 카테고리의 다른 글

Sync, Async  (0) 2023.01.26
Expression, Statement  (0) 2023.01.20

+ Recent posts