C#에는 확장 메서드(Extension Method) 기능을 지원한다.
미리 정의된 형식에 사용자 정의 함수를 추가할 수 있다.
MyMath.cs를 만들고 아래와 같이 작성한다.
이때 static class인 MyMath의 static 메서드에서 parameter에 this가 있는 MySquared가 확장 메서드가 된다.
using System;
public static class MyMath
{
/* 확장 메서드 */
public static int MySquared(this int value)
{
return value * value;
}
/* 정적 메서드 */
public static float MySafeDivide(float value, float divider)
{
if (divider == 0) return 0;
return value / divider;
}
}
확장 메서드는 정적 클래스(static class)에서만 선언가능하다.
Ctrl + Shift + N으로 빈 오브젝트를 만든 후, TestEvent.cs를 추가하자.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestEvent : MonoBehaviour
{
void Start()
{
float val1 = 5.0f;
float ret1 = MyMath.MySafeDivide(val1, 5);
Debug.Log("ret1 : " + ret1);
int val2 = 3;
int ret2 = val2.MySquared();
}
}
실행 결과는 아래와 같다.
정적 메서드 MySafeDivide를 사용하기 위해 MyMath에 . 을 붙인 후 메서드를 호출한다.
MyMath.MySafeDivide(val1, 5);
그러나 확장 메서드는 정적 메서드와 사용 방법이 다르다.
this int value에 의해 int 변수 다음에 MySquared를 호출할 수 있게 되었다.
public static int MySquared(this int value)
{
return value * value;
}
따라서 아래와 같이 사용 가능하다.
val2.MySquared();
심지어 단순한 상수에서도 호출해도 문제가 없다. (Debug.Log로 값을 찍어보면 9가 나온다.)
3.MySquared(); // 9
원한다면 정적 메서드처럼 쓰는 것도 가능하다.
이 경우에는 MyMath를 불러주고, 알맞은 parameter를 넘겨줘야 한다.
//int ret2 = val2.MySquared();
int ret2 = MyMath.MySquared(val2);
확장 메서드는 보통 namespace로 관리하여 사용한다.
위의 경우는 namespace가 없기 때문에 모든 스크립트에서 호출되므로 관리하기가 힘들 수 있다.
아래와 같이 MyMath.cs를 수정하자. MyExtensionMethod라는 이름의 namespace 안에 선언하였다.
using System;
namespace MyExtensionMethod
{
public static class MyMath
{
/* 확장 메서드 */
public static int MySquared(this int value)
{
return value * value;
}
/* 정적 메서드 */
public static float MySafeDivide(float value, float divider)
{
if (divider == 0) return 0;
return value / divider;
}
}
}
이제 TestEvent.cs에 using MyExtensionMethod; 을 추가한 스크립트에서만 확장 메서드를 호출할 수 있다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using MyExtensionMethod;
public class TestEvent : MonoBehaviour
{
void Start()
{
float val1 = 5.0f;
float ret1 = MyMath.MySafeDivide(val1, 5);
Debug.Log("ret1 : " + ret1);
int val2 = 3;
//int ret2 = MyMath.MySquared(val2);
int ret2 = val2.MySquared();
Debug.Log("ret2 : " + ret2);
}
}
이제 testObject라는 게임 오브젝트에
type이 1이면 BoxCollider를 추가하고, type이 2면 Rigidbody를 추가한다고 가정해보자.
type이 늘어나면 else if가 계속 늘어나게 된다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using MyExtensionMethod;
public class TestEvent : MonoBehaviour
{
public GameObject testObject;
void Start()
{
int type = 1;
if (type == 1) testObject.AddComponent<BoxCollider>();
else if (type == 2) testObject.AddComponent<Rigidbody>();
//else if (...)
}
}
그리고 여러 스크립트에서 이러한 Component를 추가하는 코드가 있다면,
요구사항이 추가될 경우, 모든 스크립트에 else if를 수정해야 하는 불편함이 있다.
이러한 문제점은 확장 메서드를 이용해서 아래와 같이 단 한줄로 해결할 수 있다.
testObject.MyAddComponent((MyEnum)type);
MyMath.cs에서 아래와 같이 확장메서드를 만들었다. (이름과 달리 수학과 관련된 메서드는 아니지만...)
public enum MyEnum { Nothing, MyBoxCollider, MyRigidbody }
public static class MyComponent
{
public static void MyAddComponent(this GameObject go, MyEnum type)
{
if (type == MyEnum.MyBoxCollider) go.AddComponent<BoxCollider>();
else if (type == MyEnum.MyRigidbody) go.AddComponent<Rigidbody>();
}
}
이제 확장 메서드 MyAddComponent에 else if만 추가해주면 다른 스크립트에서는 수정을 할 필요가 없어진다.
빈 오브젝트를 만들어서 TestEvent에 추가한 후, 동적으로 Rigidbody나 BoxCollider가 잘 추가 되는지 확인해보자.
아래는 TestEvent에 연결된 TestObject이다.
type == 1인 경우 BoxCollider가 동적으로 생성된 것을 알 수 있다.
최종 코드는 아래와 같다.
MyMath.cs
using System;
using UnityEngine;
namespace MyExtensionMethod
{
public enum MyEnum { Nothing, MyBoxCollider, MyRigidbody }
public static class MyComponent
{
public static void MyAddComponent(this GameObject go, MyEnum type)
{
if (type == MyEnum.MyBoxCollider) go.AddComponent<BoxCollider>();
else if (type == MyEnum.MyRigidbody) go.AddComponent<Rigidbody>();
}
}
public static class MyMath
{
/* 확장 메서드 */
public static int MySquared(this int value)
{
return value * value;
}
/* 정적 메서드 */
public static float MySafeDivide(float value, float divider)
{
if (divider == 0) return 0;
return value / divider;
}
}
}
TestEvent.cs (1)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using MyExtensionMethod;
public class TestEvent : MonoBehaviour
{
void Start()
{
float val1 = 5.0f;
float ret1 = MyMath.MySafeDivide(val1, 5);
Debug.Log("ret1 : " + ret1);
int val2 = 3;
//int ret2 = MyMath.MySquared(val2);
int ret2 = val2.MySquared();
Debug.Log("ret2 : " + ret2);
}
}
TestEvent.cs (2)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using MyExtensionMethod;
public class TestEvent : MonoBehaviour
{
public GameObject testObject;
void Start()
{
int type = 1;
testObject.MyAddComponent((MyEnum)type);
}
}
Unity Plus:
Unity Pro:
Unity 프리미엄 학습:
'개발 > Unity' 카테고리의 다른 글
유니티 쉐이더 - 속성 타입과 인터페이스 옵션 (Properties Type and Interface Attributes) (0) | 2022.06.06 |
---|---|
유니티 - 스카이 박스 변경 (Skybox) (0) | 2022.06.01 |
유니티 - JsonUtility로 Json 파싱하기 : (2) 배열 파싱 (1) | 2022.05.29 |
유니티 - JsonUtility로 Json 파싱하기 : (1) 기본 (0) | 2022.05.29 |
유니티 - 런타임 시 프리팹에 스크립트 추가하기 (Attach Script when Instantiate a Prefab) (0) | 2022.05.29 |
댓글