2020. 12. 23. 15:34
Unity/C#
현재 클래스 명
public class ParentClass
{
public class TestClass
{
public void Log()
{
var className = GetType().Name
Debug.Log(className); //TestClass가 나옴
}
}
}
현재 클래스 명 (부모포함)
var className = typeof(TestClass).FullName
Debug.Log(className); //ParentClass+TestClass가 나옴
해당 클래스가 존재하는지
public static bool CheckClassExists(string className)
{
return System.Type.GetType(className) != null;
}
현재 함수 명
var methodName = System.Reflection.MethodBase.GetCurrentMethod().Name;
Debug.Log(methodName);
필드명들
string[] GetClassFieldNames<T>(T targetClass)
{
var fields = typeof(T).GetFields();
return System.Array.ConvertAll(fields, x => x.Name);
}
필드명들2
string[] GetClassFieldNames<T>(T targetClass)
{
var fields = typeof(T).GetFields();
return Array.ConvertAll(fields, x => $"{x.Name} - type: {x.FieldType}");
}
특정클래스의 필드명과 함수명에 접근
var methods = typeof(Class).GetMethods();
foreach (var method in methods)
{
EditorGUILayout.LabelField(method.Name);
}
var fields = typeof(Class).GetFields();
foreach (var field in fields)
{
EditorGUILayout.LabelField(field.Name);
}
클래스할당과 연동
구조체에는 씨알도 안 먹히니 헛고생 하지 말자
public class SampleClass
{
string numStr = "0.5";
int num = 1;
float value = 1.5f;
public SampleClass() { }
public SampleClass (string stringData)
{
var fields = typeof(SampleClass).GetFields();
var targetClass = this;
for (int i = 0; i < fields.Length; i++)
{
if (fields[i].FieldType == typeof(string))
{
fields[i].SetValue(targetClass, stringData);
}
else if (fields[i].FieldType == typeof(bool))
{
fields[i].SetValue(targetClass, bool.Parse(stringData));
}
else if (fields[i].FieldType == typeof(char))
{
fields[i].SetValue(targetClass, char.Parse(stringData));
}
else if (fields[i].FieldType == typeof(int))
{
fields[i].SetValue(targetClass, int.Parse(stringData));
}
else if (fields[i].FieldType == typeof(uint))
{
fields[i].SetValue(targetClass, uint.Parse(stringData));
}
else if (fields[i].FieldType == typeof(long))
{
fields[i].SetValue(targetClass, long.Parse(stringData));
}
else if (fields[i].FieldType == typeof(ulong))
{
fields[i].SetValue(targetClass, ulong.Parse(stringData));
}
else if (fields[i].FieldType == typeof(float))
{
fields[i].SetValue(targetClass, float.Parse(stringData));
}
else if (fields[i].FieldType == typeof(double))
{
fields[i].SetValue(targetClass, double.Parse(stringData));
}
else
{
fields[i].SetValue(targetClass, stringData);
}
}
}
public override string ToString()
{
var fields = GetType().GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
return string.Join("\n",System.Array.ConvertAll(fields, x => $"{x.Name}: {x.GetValue(x)}" ));
}
/*
public override string ToString()
{
var fields = typeof(SampleClass).GetFields();
string returnString = "";
for (int i = 0; i < fields.Length; i++)
{
if (i>0)
{
returnString += "\n";
}
returnString += $"{fields[i].Name}:{fields[i].GetValue(this)}";
}
return returnString;
}
*/
public static implicit operator string(SampleClass _this) //암시적 형변환, 명시적은 explicit
{
return _this.ToString();
}
}
public class MainClass : MonoBehaviour
{
void Start()
{
Debug.Log("new SampleClass()\n" + new SampleClass());
Debug.Log("new SampleClass(\"123\")\n" + new SampleClass("123"));
}
}
생성자 자동 할당
public class SampleClass
{
public int number;
public string name;
public SampleClass()//생성자(자동)
{
var targetClass = new SampleClass(123, "Name");
//this.number = targetClass.number;
//this.name = targetClass.name;
//이렇게 안쳐도 됨
var fields = GetType().GetFields();
foreach (var field in fields)
{
field.SetValue(this, field.GetValue(targetClass));
}
}
public SampleClass(int number, string name)//생성자
{
this.number = number;
this.name = name;
}
}
클래스 깊은복사, 간단한 형식만 된다. 다중 클래스등은 불가 (문자열도 안되는듯?)
public class SampleClass
{
public int number;
public string name;
public SampleClass Clone()
{
var targetClass = new SampleClass();
var fields = GetType().GetFields();
foreach (var field in fields)
{
field.SetValue(this, field.GetValue(targetClass));
}
return targetClass;
}
}
위에거의 외부버전
https://gist.github.com/ahzkwid/69d7703736b5bca29b0131270ee9164a
static void CopyClass<T>(T source, T target)
{
var fields = target.GetType().GetFields();
foreach (var field in fields)
{
field.SetValue(target, field.GetValue(source));
}
}
BindingFlags 옵션들 (지정 안되면 논퍼블릭까지 전부 반환함)
System.Reflection.BindingFlags.NonPublic //퍼블릭이 아닌것들
System.Reflection.BindingFlags.Public //퍼블릭인것들
System.Reflection.BindingFlags.Instance //일반적인 변수들 (지역변수)
System.Reflection.BindingFlags.Static //전역변수들
//예시 (일반적인 필드값 불러오기)
var fields = GetType().GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
Type검사
field.FieldType.IsValueType //bool,int,float
field.FieldType.IsArray //bool[], int[], float[]
field.FieldType.IsClass //bool[], int[], float[], string, SubClass
field.FieldType.IsEnum //Enum타입
field.FieldType.Equals(typeof(string)) //string
//클래스인지 검사
var fieldType = field.FieldType;
if (fieldType.IsClass&&(fieldType.IsArray==false)&&(fieldType.Equals(typeof(string)) == false))
{
//Sub클래스일경우에만
}
//List인지 검사
if((fieldType.IsGenericType) && fieldType.GetGenericTypeDefinition() == typeof(List<>))
오브젝트에서 ?배열을 반환
이런 X같은 코드도 쓸데가 있다
object objData;
var arrDatas = (System.Collections.IList)objData;
Debug.Log($"arrDatas[0]: {arrDatas[0]}");
Debug.Log($"arrDatas[1]: {arrDatas[1]}");
Debug.Log($"arrDatas.Count: {arrDatas.Count}");
오브젝트 리스트나 오브젝트 배열을 특정 형배열로 변환
using System.Linq;
//오브젝트 리스트를 float 배열로 변환
var objList=new List<object>();
float[] floatArray=objList.Cast<float>().ToArray();
//오브젝트 배열을 string 배열로 변환
object[] objArray = new object[1];
string[] stringArray = objArray.Cast<string>().ToArray();
문자열을 FieldType으로 변환
var text = "105.0";
var converter = TypeDescriptor.GetConverter(field.FieldType);
var data = converter.ConvertFrom(text);
field.SetValue(tempClass, data);
배열에 할당된 변수명 추출
v1
더보기
string[] ArrayToFieldNames(object containingClassWithArray, object[] array)
{
var fields = containingClassWithArray.GetType().GetFields();
var fieldNames = System.Array.ConvertAll(array, x => fields.First(field => field.GetValue(containingClassWithArray) == x).Name);
return fieldNames;
}
/*
예시
public class Coordinator : MonoBehaviour
{
public BodyPart head;
public BodyPart top;
public BodyPart bottom;
public BodyPart gloves;
public BodyPart shoes;
public BodyPart hair;
public BodyPart eye;
public BodyPart skin;
public BodyPart[] bodyParts
{
get
{
return new BodyPart[] { head, top, bottom, gloves, shoes, hair, eye, skin };
}
}
}
이렇게 있을때
var bodyPartNames = ArrayToFieldNames(coordinator, coordinator.bodyParts);
Debug.Log(string.Join(",",bodyPartNames));
하면 head,top,bottom,gloves,shoes,hair,eye,skin로 나온다
*/
v2
v1과 구조상으로는 동일한데 클래스내부로 넣어버렸다.
이게 더 편함
string[] ArrayToFieldNames(object[] array)
{
var fields = GetType().GetFields();
var fieldNames = System.Array.ConvertAll(array, x => fields.First(field => field.GetValue(this) == x).Name);
return fieldNames;
}
/*
//샘플
public BodyPart head;
public BodyPart top;
public BodyPart bottom;
public BodyPart gloves;
public BodyPart shoes;
public BodyPart hair;
public BodyPart eye;
public BodyPart skin;
public BodyPart[] bodyParts
{
get
{
return new BodyPart[] { head, top, bottom, gloves, shoes, hair, eye, skin };
}
}
public string[] bodyPartNames
{
get
{
return ArrayToFieldNames(bodyParts);
}
}
*/
근데 이방법 쓸바엔 그냥 클래스 안에 name값 넣어서 써라
var value = field.GetValue(component);
if (value==null)
{
continue;
}
https://x.com/ahzkwid/status/1799549808312746276
field.GetValue(component)을 ==null체크시 정상동작하지 않는 현상이 있는데
var value = field.GetValue(component);
if (value==null)
{
continue;
}
if (value.Equals(null))
{
continue;
}
이렇게 하면 된다
'Unity > C#' 카테고리의 다른 글
MapBorder (0) | 2020.12.24 |
---|---|
그래디언트효과 (0) | 2020.10.20 |
유니티 에디터 관련 (0) | 2020.10.05 |