목표

  • 접근 한정자(access modifiers 혹은 visibility modifier)에 대해 알아보자.

접근 지시자는 강력하지만, 현실은 Public

접근 한정자 (access modifiers)

  • 접근 한정자는 외부로부터 접근을 제한할 때 사용된다.
  • 아래 설명에서 동일 어셈블리란 exe나 dll 등의 빌드 결과물을 말한다.
접근 한정자설명
public모든 접근을 허용한다.
protected파생형 클래스에서만 접근을 가능하게 한다.
private동일 클래스 내의 멤버만 접근 가능하다.
internal동일한 어셈블리에서만 접근 가능하다.
주로 SDK 개발에 사용되는 키워드이다.
protected internal동일한 어셈블리 또는 파생형에서만 접근 가능하다.
internal의 접근을 제한적으로 허용하기 위해 사용된다.
private protected동일한 클래스 또는 동일한 어셈블리 내의 파생형에서만 접근 가능하다.

public & protected & private

public class ProtectedClass()
{
    public ProtectedClass()
    {
        // private 함수는 오직 함수가 정의된 클래스 내부에서만 접근할 수 있다.
        CallPrivate();
    }

    private void CallPrivate()
    {
        // CallPublic()은 어디서든지 호출할 수 있다.
    }

    public void CallPublic()
    {
        // CallPublic()은 어디서든지 호출할 수 있다.
    }

    protected void CallProtected()
    {
        // CallPublic()은 어디서든지 호출할 수 있다.
    }

}

// ProtectedClass를 상속 받은 파생형 객체
public class DerivedProtectedClass : ProtectedClass
{
    public void CallParentProtected()
    {
        base.CallProtected();
    }
}

public class SampleScript : MonoBehaviour
{
    ProtectedClass pClazz = new ProtectedClass();

    DerivedProtectedClass dpClazz = new DerivedProtectedClass();

    public void Start()
    {
        // public 함수는 노출되지만, protected는 노출되지 않는다.
        pClazz.CallPublic();

        // 상속을 받았으니 당연히 public 함수가 노출된다.
        dpClazz.CallPublic();

        // 상속을 받아도 protected의 경우 외부에서 호출할 수 없다.
        // 좋은 방법은 아니지만 파생형 클래스에서 부모 클래스에 접근하는 
        // public 함수를 정의하면 외부에서도 protected에 접근 가능하다. 
        // 이러면 접근 제한자를 쓰는 의미가 없잖아?
        dpClazz.CallParentProtected();
    }
}

internal

  • internal을 테스트해보기 위해서는 Unity C#를 DLL을 만들어보면 된다.
    • Unity C# 코드 DLL 만들기
    • 이렇게 만들어진 DLL은 Unity Script 뭉치로 보면 된다.
    • DLL을 만들었다면 SampleScript에서 DataCenter의 함수들을 호출해보자.
    • CallPublic 함수만 노출된다.
    • CallInternal 함수는 DataCenter 내부에서만 사용 가능하게 만든 함수 이므로 이렇게 노출되는게 정상이다.

VisualStudio에서 Unity용 DLL로 빌드한 DataCente.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

namespace Data
{
    public class DataCenter
    {
        public void CallPublic()
        {
            Debug.Log("public method call!!");
        }

        protected void CallProtected()
        {
            Debug.Log("protected method call!!");
        }

        private void CallPrivate()
        {
            Debug.Log("private method call!!");
        }

        internal void CallInternal()
        {
            Debug.Log("internal method call!!");
        }

        protected internal void CallProtectedInternal()
        {
            Debug.Log("protected internal method call!!");
        }
    }
}

DataCenter를 호출하는 Unity Sample Script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Data;

public class SampleScript : MonoBehaviour
{
    DataCenter dataCenter = new DataCenter();

    // Start is called before the first frame update
    void Start()
    {
        dataCenter.CallPublic();
    }
}
  • 이 상황에서 internal을 호출하려면 InternalsVisibleToAttribute을 사용해야 한다.
  • 이는 internal의 접근 제어 효과를 깨트리는 방법이다.
    • C++ 프로젝트에서도 간혹 Friend 키워드가 있다고 사용하는 사람들이 있는데, 한번 끌려가서 비오는날 Unix Timestamp 만큼 처맞아 보야
    • 정말 필요한 상황이 아니면 쓰지 말도록 하자.

protected internal

  • DataCenter를 상속 받으면 protected internal에 접근할 수 있다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Data;

public class DerivedDataCenter : DataCenter
{
    public DerivedDataCenter()
    { 
        base.CallProtectedInternal();
    }
}

private protected

  • 이건 C# Version 7.2에 추가된 문법이다.
  • Unity 2019.3 이상 버전에서는 C# 8.0을 지원하지만, 2018.x 버전에서는 지원하지 않는다.
  • 따라서 범용성이 떨어져, Unity C#에서 private protected 구현은 Pass!!

정리

  • 사실 게임 개발에는 주로 public이나 public이나 public이 사용된다.
  • 사실 게임 개발에는 주로 public, protected, private만 사용된다.
  • internal이나 protected internal은 Plugin 제작시 사용되는데, 7년 일하면서 protected internal은 책에서만 본것 같다.

+ Recent posts