[英]C# How would I get a field through reflection once and make a delegate that returns its value for future use?
我的用例:在我的游戲中,我有一個覆蓋層,用於跟蹤具有“[TrackedField]”屬性的任何字段。 我希望它顯示變量的名稱和當前值。 反射是一個有點昂貴的操作,我一直在尋找一種方法來通過反射檢索一次值,然后創建一個不使用反射的委托函數來返回字段的值。 這樣,只要我想更新疊加層上的值,就可以調用它。
我實際上不知道我要問的是否可行,或者是否有更好的方法來檢索此值。 過去幾天我已經四處搜索,但我能挖掘到的只是這個相關的帖子。 它很可能每秒更新多次,所以如果可以的話,我想避免重復使用反射。
目前,我的代碼只獲取每個變量名稱(或屬性中定義的標簽),並使用一個僅讀取“錯誤”的虛擬委托來顯示它:
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)]
如果你很好奇,它會在覆蓋層上產生這個結果。
如果您對屬性的外觀感興趣:
[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; }
}
}
我從未使用過 Unity,但在經典的 .NET Framework 中這是可能的:
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);
我也沒有使用過Unity。 您可以嘗試替換您的委托() => { return "error"; }
() => { return "error"; }
用
() => { return objectFields[i].GetValue(mono); }
請注意,此委托將返回一個對象,以防萬一您應該處理null
值。
此外,它仍然是一個昂貴的調用,但至少你減少了查找字段和枚舉屬性,這些操作是高成本的操作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.