[英]Get memory address of field using reflection (C#)
在.Net Core中,當在編譯時不知道父對象時,如何獲取原始字段的內存地址(IntPtr)?
如果對象類是struct和blittable,則可以使用Marshel.Offset,但不幸的是,它不是。
下面的代碼說明了我正在嘗試做的事情
class Example // this class is defined in a different assembly and is not known at compile time
{
public double foo;
}
static void Main(string[] args)
{
Example obj = new Example();
obj.foo = 123;
var hdl = GCHandle.Alloc(obj, GCHandleType.Pinned);
IntPtr foo_add = GetAddressOf(obj, "foo");
hdl.Free();
}
static IntPtr GetAddressOf(object pinned_object, string field_name)
{
FieldInfo field = pinned_object.GetType().GetField(field_name);
return field.GetFieldAddress(pinned_object); // Unfortunatly this function does not exist, what are the alternatives?
}
另一個問題是獲取對象的內存地址,這可以使用GCHandle.Alloc完成,不適用於原語。
以下答案描述了如何使用C#7.0中的“引用返回”功能來獲取對字段的托管引用:
https://stackoverflow.com/a/45046664/425678
基於這個絕妙的答案,我們可以修改函數create_refgetter
以獲得非托管指針。 這利用了鮮為人知的函數__makeref,該函數在處理泛型類型時需要使用( 詳細說明 )
然后,此函數與函數GetAddressOf
一起包裝,該函數允許在不指定泛型的情況下進行調用。
static IntPtr GetAddressOf(object pinned_object, string field_name)
{
var fi_val = pinned_object.GetType().GetField(field_name);
var mi_all = typeof(Program).GetMethod("create_refgetter", BindingFlags.Static | BindingFlags.Public);
var mi_generic = mi_all.MakeGenericMethod(pinned_object.GetType(), fi_val.FieldType);
var ptr = (IntPtr) mi_generic.Invoke(null, new object[] {pinned_object, field_name });
return ptr;
}
https://stackoverflow.com/a/45046664/425678
public delegate ref U RefGetter<T, U>(T obj);
public static IntPtr create_refgetter<T, U>(object obj,string s_field)
{
const BindingFlags bf = BindingFlags.NonPublic |
BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.DeclaredOnly;
var fi = typeof(T).GetField(s_field, bf);
if (fi == null)
throw new MissingFieldException(typeof(T).Name, s_field);
var s_name = "__refget_" + typeof(T).Name + "_fi_" + fi.Name;
// workaround for using ref-return with DynamicMethod:
// a.) initialize with dummy return value
var dm = new DynamicMethod(s_name, typeof(U), new[] { typeof(T) }, typeof(T), true);
// b.) replace with desired 'ByRef' return value
dm.GetType().GetField("m_returnType", bf).SetValue(dm, typeof(U).MakeByRefType());
var il = dm.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldflda, fi);
il.Emit(OpCodes.Ret);
RefGetter<T, U> ref_getter = (RefGetter<T, U>)dm.CreateDelegate(typeof(RefGetter<T, U>));
unsafe
{
TypedReference t_ref = __makeref(ref_getter((T)obj));
IntPtr ptr = *((IntPtr*)&t_ref);
return ptr;
}
}
}
〔實施例:
class Example // this class is defined in a different assembly and is not known at compile time
{
public double foo;
}
static void Main(string[] args)
{
Example obj = new Example();
obj.foo = 123;
var hdl = GCHandle.Alloc(obj);
unsafe
{
IntPtr foo_add = GetAddressOf(obj, "foo");
double* ptr = (double*) foo_add;
Console.WriteLine("Current Value: {0}", *ptr);
*ptr = 4;
Console.WriteLine("Updated Value: {0}", obj.foo);
}
hdl.Free();
Console.ReadLine();
}
示例輸出:
Current Value: 123
Updated Value: 4
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.