구조체
public struct mVec3
{
public float x, y, z;
public float Length
{
get
{
return (float)(Math.Sqrt((x * x) + (y * y) + (z * z)));
}
set
{
//float _t=Length*value;
//float _t=value/(float)(Math.Sqrt((x*x)+(y*y)+(z*z)));
if (Length <= 0)
{
z = value;
}
else
{
float _t = value / Length;
x *= _t;
y *= _t;
z *= _t;
}
}
}
public static mVec3 forward //절대적
{
get
{
return new mVec3(0f,0f,1f);
}
}
public mVec3 up //상대적
{
get
{
return new mVec3((Quaternion.Euler( this.x,this.y,this.z) * Quaternion.Euler(90f,0f,0f)).eulerAngles);
//return mScript.len_vec(this);
}
}
public mVec3() : this(1,2,3)//생성자 (x:1,y:2,z:3)
{
}
public mVec3(float X, float Y, float Z)//생성자
{
this.x = X;
this.y = Y;
this.z = Z;
}
public static mVec3 operator ++(mVec3 _Vec)
{
_Vec.x++;
_Vec.y++;
_Vec.z++;
return _Vec;
}
public static mVec3 operator /(mVec3 _Vec1, mVec3 _Vec2)
{
_Vec1.x /= _Vec2.x;
_Vec1.y /= _Vec2.y;
_Vec1.z /= _Vec2.z;
return _Vec1;
}
public static explicit operator mVec4(mVec3 _this) //명시적 형변환, 암시적은 implicit
{
mVec4 _return;
_return.x=_this.x;
_return.y=_this.y;
_return.z=_this.z;
_return.w=0;
return _Vec;
}
public static bool operator ==(mVec3 _Vec1, mVec3 _Vec2)
{
foreach (var field in typeof(mVec3).GetFields())
{
if (field.GetValue(_Vec1) != field.GetValue(_Vec2))
{
return false;
}
}
return true;
}
public static bool operator !=(mVec3 _Vec1, mVec3 _Vec2)
{
return !(questionDictionary1== questionDictionary2);
}
}
사용시
//public static mVec3 zero(0f,0f,0f);
Enum
public enum UpperPath
{
persistentDataPath
, dataPath
, streamingAssetsPath
, temporaryCachePath
};
Enum 길이 반환
int enumCount=System.Enum.GetValues(typeof(EnumName)).Length;
Category[] openCategorysIndexes = (Category[])System.Enum.GetValues(typeof(Category));
namespace가 아닌 class using
using static SampleClass;
using문
using (var streamReader = new System.IO.StreamReader(response))
{
string result = streamReader.ReadToEnd();
streamReader.Close();
return result;
}
자주쓰는데 은근 겁나 까먹음
try
{
}
catch(Exception ex)
{
Debug.Log(ex.ToString());
}
변수이름
string 변수명=nameof(변수);
타입 이름
typeof(AudioClip).Name
c#버전 #define
public const float PointMax = 2;
public float Point = PointMax;
C#의 실제 #define
버전관리할때 유용함
#define Ver1000
#define Ver1001
#if Ver1000
//여기서 동작함
#elif Ver1001
//Ver1001일때 작동함
#else
//그것도 아닐때
#endif
///함수주석
/// <summary>
/// 이름을 GUI에 표시함
/// </summary>
/// <param name="wordDictionary">이름</param>
/// <param name="wid">가로크기</param>
/// <param name="hei">세로크기</param>
void DrawWordDictionary(string Name, int wid, int hei)
{
}
널은 안됨
class NotNullContainer<T> where T : notnull
{
}
new한정자
new가 붙은거만 넣을수 있음
public static T GetClass<T>(string text) where T : new()
{
if(text=="ok")
{
var targetClass = new T();
return targetClass;
}
else
{
return null;
}
}
is 연산자
어디서 온건지 알 수 없는 obj등을 처리할 때 쓰인다
if ((objData is Dictionary<string, object>)==false)
{
Debug.LogError("objData는 Dictionary<string, object>가 아닙니다");
return;
}
//아래와 동일함
if ((objData.GetType() == typeof(Dictionary<string, object>))==false)
{
Debug.LogError("objData는 Dictionary<string, object>가 아닙니다");
return;
}
as 연산자
캐스팅 연산자인데 좀 복잡함 아래 참고
서로 동일한 코드를 나타내고 있다
string text= obj as string;
//위아래 동일함
string text;
if (obj is string)
{
text = (string)obj;
}
else
{
text = null;
}
if else 간소화 (남용은 금지, 복수로 쓰게될경우 가독성이 개판된다)
bool A;
if (B)
{
A = C;
}
else
{
A = D;
}
//위아래 동일
bool A=B?C:D;
null체크 간소화
if (A != null)
{
if (B != null)
{
return C;
}
}
return null;
//위아래 동일
return A?.B?.C;
?[]연산 에러발생시 null반환
다만 인덱스 오류는 캐치가 안 된다
string text = null;
if (array!=null)
{
text = array[1];
}
//위아래 동일
var text = array?[1];
아래건 동일분기 처리를 좀 알아봐야 겠다
switch 간소화 (유니티 안됨, 비주얼스튜디오 2019 자동화 안됨)
switch(condition)
{
case 1:
A=B;
break;
case 2:
A=C;
break;
default:
A=D;
break;
}
//위아래 동일
condition switch
{
1 => A=B;
2 => A=C;
_ => A=D;
}
튜플
void Start()
{
var (min, max) = FindMinMax(1, 2, 3, 4);
Debug.Log("min: " + min);
Debug.Log("max: " + max);
}
(int min, int max) FindMinMax(params int[] input)
{
var min = Mathf.Min(input);
var max = Mathf.Max(input);
return (min, max);
}
여러개 리턴할때 사용
유니티도 된다
??연산
null처리할때 좋음
아래 네개 모두 동일한 코드이다
string a = null;
Debug.Log(a ?? "ABC"); //ABC반환
a = "a";
Debug.Log(a ?? "BCD"); //a반환
//위아래 동일
string a = null;
Debug.Log(a is string ? a:"ABC"); //ABC반환
a = "a";
Debug.Log(a is string ? a:"BCD"); //a반환
//위아래 동일
string a = null;
Debug.Log(a==null ? "ABC":a); //ABC반환
a = "a";
Debug.Log(a==null ? "BCD":a); //a반환
//위아래 동일
string a = null;
if(a!=null)
{
Debug.Log(a);
}
else
{
Debug.Log("ABC");
}
a = "a";
if(a!=null)
{
Debug.Log(a);
}
else
{
Debug.Log("BCD");
}
인덱스 체크 간소화
근데 어차피 쓰려면 null체크 추가로 들어가서 그렇게 효율적이진 않음
오히려 협업할때는 누구나 알기쉬운 위쪽이 나을수도 있겠다
if((index >= 0)&&(index < array.Length))
{
var item = array[index];
//작동할 코드
}
//위아래 동일
var item = array.ElementAtOrDefault(index);
if(item != null)
{
//작동할 코드
}
로컬함수
외부로 표출될 필요가 없는 함수 작성시 매우매우 유용하다.
특히 최장점은 같은 이름의 함수를 여러군데서 쓸수있다는 점
함수를 사용할때마다 생성하는 방식인지
성능을 절약하기 위해 static을 붙이라는 문구가 뜨는데 유니티 2019에서는 미지원이다
void SampleFunction()
{
Debug.Log(LocalFunction("test")); //long text
Debug.Log(LocalFunction("te")); //short text
Debug.Log(LocalFunction("")); //short text
string LocalFunction(string text)
{
if(text.Length>2)
{
return "long text";
}
return "short text";
}
}
모든 스크립트에 using을 적용
몰론 함부로 쓰면 ㅈ된다
global using System;
함수내부 조건식 Predicate
public static class Array
{
//Array.FindIndexAll(arr,x=>x>1);
//혹은 arr.FindIndexAll(x=>x>1);
public static int[] FindIndexAll<T>(this T[] array, System.Predicate<T> match)
{
var indexList = new List<int>();
for (int i = 0; i < array.Length; i++)
{
if (match.Invoke(array[i]))
{
indexList.Add(i);
}
}
return indexList.ToArray();
}
//2개인자
//Array.FindAll(arr,x=>x.Item1>x.Item2)
public static int[] FindAll<T>(T[] array, System.Predicate<(T previous,T target)> match)
{
var indexList = new List<int>();
for (int i = 0; i < array.Length; i++)
{
if (match.Invoke((array[i-1],array[i])))
{
indexList.Add(i);
}
}
return indexList.ToArray();
}
}