2017-10-22 1 views
1

사용 사례 : 게임에서 '[TrackedField]'속성을 가진 모든 필드를 추적하는 오버레이가 있습니다. 변수의 이름과 현재 값을 표시하고 싶습니다. 리플렉션은 값 비싼 연산이므로 리플렉션을 통해 값을 한 번 검색 한 다음 리플렉션을 사용하지 않는 델리게이트 함수를 만들어 필드 값을 반환하는 방법을 찾고있었습니다. 그렇게하면 오버레이에서 해당 값을 업데이트하려고 할 때마다이 메서드를 호출 할 수 있습니다.C# 리플렉션을 통해 필드를 한 번 가져 와서 나중에 사용할 수 있도록 값을 반환하는 대리자를 만드는 방법은 무엇입니까?

내가 묻는 것이 가능할 지, 아니면이 값을 검색하는 더 좋은 방법이 있는지 실제로 알지 못합니다. 나는 지난 몇 일 동안 주위를 수색했지만, 내가 파낼 수 있었던 것은 모두 this related post이었다. 대부분 초당 여러 번 업데이트되므로 가능한 경우 반사를 반복해서 사용하지 않는 것이 좋습니다.

현재 내 코드는 (속성 정의 또는 레이블) 모든 변수 이름을 가져옵니다 그냥 "오류"를 읽고 더미 대표로 표시됩니다 여기에

MonoBehaviour[] sceneActive = GameObject.FindObjectsOfType<MonoBehaviour>(); 

foreach (MonoBehaviour mono in sceneActive) 
{ 
    System.Type monoType = mono.GetType(); 

    // Retreive the fields from the mono instance 
    FieldInfo[] objectFields = monoType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 

    // search all fields and find the attribute [TrackedField] 
    for (int i = 0; i < objectFields.Length; i++) 
    { 
     TrackedFieldAttribute attribute = Attribute.GetCustomAttribute(objectFields[i], typeof(TrackedFieldAttribute)) as TrackedFieldAttribute; 

     // if we detect any attribute add it to the overlay 
     if (attribute != null) 
     { 
      trackerBar.AddTab(attribute.label == null ? objectFields[i].Name : attribute.label,() => { return "error"; },attribute.color); 
     } 
    } 
} 

은 '[의 예 TrackedField 행동] '속성 : 당신은 호기심이 있다면

[TrackedField] 
private bool consoleOpen = false; 
[TrackedField("MyLabel")] 
private bool overlayShown = false; 
[TrackedField("ColoredLabel", 50, 50, 255)] 

그것은 오버레이 this 발생합니다.

그리고 당신은 속성이 어떻게 생겼는지에 관심이 있다면 :

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] 
public class TrackedFieldAttribute : Attribute 
{ 
    private string _label; 
    private Color _color; 

    public TrackedFieldAttribute() 
    { 
     _label = null; 
     _color = default(Color); 
    } 

    public TrackedFieldAttribute(string label) 
    { 
     _label = label; 
     _color = default(Color); 
    } 

    public TrackedFieldAttribute(float red = 0, float green = 0, float blue = 0) 
    { 
     _label = null; 
     _color = new Color(red/255f, green/255f, blue/255f); 
    } 

    public TrackedFieldAttribute(string label, float red = 0, float green = 0, float blue = 0) 
    { 
     _label = label; 
     _color = new Color(red/255f, green/255f, blue/255f); 
    } 

    public string label 
    { 
     get { return _label; } 
     set { _label = value; } 
    } 

    public Color color 
    { 
     get { return _color; } 
     set { _color = value; } 
    } 
} 
+0

Unity에서 리플렉션을 사용하지 마십시오. 왜 이것을 필요로합니까? 어쩌면 반사없이 해결 방법이 있습니다 .... – Programmer

+0

일반적인 디버깅 도구입니다. 아직 '[TrackedField]'속성을 사용할 수있는 해결 방법이 있다면 나는 그것을 모두 얻게 될 것입니다. – Afropenguinn

답변

1

나는이 가능하다 고전 .NET 프레임 워크에 단결 만에를 사용한 적이 :

public class FieldAccessor 
{ 
    private delegate object FieldGetter(object instance);  
    private FieldGetter getter; 

    public FieldAccessor(FieldInfo field) 
    { 
     ParameterExpression instanceParameter = Expression.Parameter(typeof(object), "instance"); 

     MemberExpression member = Expression.Field(
      field.IsStatic ? null : Expression.Convert(instanceParameter, field.DeclaringType), // (TInstance)instance 
      field); 

     LambdaExpression lambda = Expression.Lambda<FieldGetter>(
      Expression.Convert(member, typeof(object)), // object return type 
      instanceParameter); // instance (object) 

     getter = (FieldGetter)lambda.Compile(); 
    } 

    public object Get(object instance) 
    { 
     return getter(instance); 
    } 
} 

사용법 :

FieldInfo fi = typeof(MyType).GetField(...); 

// creating the accessor is slow so cache this accessor instance: 
var accessor = new FieldAccessor(fi); 

// and then just use it like this: 
var value = accessor.Get(myInstance); 
+0

'DeclaringType'을 호출 할 수 없거나 정확한 네임 스페이스를 찾지 못했습니다. Mono Unity 사용 버전에는 존재하지 않을 수 있습니다. – Afropenguinn

+0

아, 신경 쓰지 마세요. 필드 매개 변수의 선언 유형입니다. 나는 그것을 일반적으로 사용하려고 노력했다. – Afropenguinn

+0

당신은 맞고 고정되어 있습니다. 그것은 내 버전의 속성이었습니다. – taffer

0

유니티도 사용하지 않았습니다. 이 대표는 객체를 반환하고 단지 경우에 당신이 null 값을 처리해야

() => { return objectFields[i].GetValue(mono); } 

참고하여 대리자를 () => { return "error"; } 대체하려고 할 수 있습니다.

또한 값 비싼 호출이지만 적어도 값 비싼 작업 인 필드를 찾고 열거 형을 열거 한 것은 아닙니다.

+0

이것은 또한 작동하며 매우 깨끗해 보입니다! 성능면에서 [taffer 's] (https://stackoverflow.com/a/46878336/2936627) 솔루션과 어떻게 비교됩니까? – Afropenguinn

+0

이 솔루션은 모든 호출에서 리플렉션을 사용하지만 다른 솔루션은 일반 필드 액세스 (인스턴스화 후)만큼 빠릅니다. – thehennyy

관련 문제