c# - __makeref 作为在 C# 中获取引用值的一种方式?

标签 c# clr

我看过这段代码,用来显示引用值:

static void Main(string[] args)
{
    string s1 = "ab";
    string s2 = "a"+"b";
    string s3 = new StringBuilder("a").Append("b").ToString();

    Console.WriteLine(GetMemoryAddress(s1));
    Console.WriteLine(GetMemoryAddress(s2));
    Console.WriteLine(GetMemoryAddress(s3));
}

static IntPtr GetMemoryAddress(object s1)
{
    unsafe
    {
        TypedReference tr = __makeref(s1);
        IntPtr ptr = **(IntPtr**) (&tr);
        return ptr;
    }
}

结果(如预期):

enter image description here

(我知道这里需要字符串实习,但这不是问题)。

问题:

虽然看起来它确实能完成工作, 使用 __makeref 是否是在 C# 中获取引用值的正确方法?

或者在任何情况下这个 ^ 会失败......?

最佳答案

Although it seems that it does do the job, Does using __makeref is this the right way of getting the reference value in c#?

在 C# 中没有执行此操作的“正确方法”——这不是你想要尝试和做的事情,但是:就它正在做什么而言——这本质上是依赖于 TypedReference 的内部布局和类型强制;它会工作(只要 TypedReference 内部没有改变——例如 TypeValue 的顺序code> fields changes),但是……这很讨厌。

还有一种更直接的方法;在 IL 中,您可以静默地将托管指针 转换为非托管指针。这意味着你可以做一些令人讨厌的事情,比如:

unsafe delegate void* RefToPointer(object obj);
static RefToPointer GetRef { get; } = MakeGetRef();
static RefToPointer MakeGetRef()
{
    var dm = new DynamicMethod("evil", typeof(void*), new[] { typeof(object) });
    var il = dm.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ret);
    return (RefToPointer)dm.CreateDelegate(typeof(RefToPointer));
}

现在你可以做:

var ptr = new IntPtr(GetRef(o));
Console.WriteLine(ptr);

这是可怕的,你永远不应该这样做 - 当然 GC 可以在你不看的时候移动东西(甚至当你正在看的时候) ,但是......它有效。

ref-emit 是否比未记录和不受支持的语言功能“更好”,例如 __makeref 和类型强制转换:是一个有争议的问题。希望是纯粹的学术辩论!

关于c# - __makeref 作为在 C# 中获取引用值的一种方式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55514705/

相关文章:

c# - 更新通用列表中元素的最佳方法

c# - GCHandle.FromIntPointer 没有按预期工作

.net - 在 SQL Server 中使用 C# 汇编

c# - Entity Framework 中 DataGrid (WPF) 的优雅过滤

c# - 避免使用托管语言的分支

c# - 无法写入 Windows Phone 中的文本文件

c# - 为 JVM 实现 C#

c# - 为什么是 str = str.Replace().Replace();比 str = str.Replace(); 快str = str.替换()?

c# - C# 未初始化的变量危险吗?

c# - sqlDecimal 到十进制 clr 存储过程无法将类型 'System.Data.SqlTypes.SqlDecimal' 的对象转换为类型 'System.IConvertible'