写点什么

除了按值和引用,方法参数的第三种传递方式

作者:EquatorCoco
  • 2024-08-23
    福建
  • 本文字数:1847 字

    阅读完需:约 6 分钟

一、官方描述


三种参数传递方式并非我们杜撰出来的,而是写在.NET 最核心的规范文档 ECMA-355 中(I.12.4.1.5),原文如下:


The CLI supports three kinds of parameter passing, all indicated in metadata as part of the signature of the method. Each parameter to a method has its own passing convention (e.g., the first parameter can be passed by-value while all others are passed byref). Parameters shall be passed in one of the following ways (see detailed descriptions below):

  • By-value – where the value of an object is passed from the caller to the callee.

  • By-reference – where the address of the data is passed from the caller to the callee, and the type of the parameter is therefore a managed or unmanaged pointer.

  • Typed reference – where a runtime representation of the data type is passed along with the address of the data, and the type of the parameter is therefore one specially supplied for this purpose.

It is the responsibility of the CIL generator to follow these conventions. Verification checks that the types of parameters match the types of values passed, but is otherwise unaware of the details of the calling convention.


三种参数传递方式如下:


  • By-value:传递参数的值或者拷贝。这里所谓的值分两种情况,对于值类型,变量的值就是承载目标值的字节,比如参数类型是一个我们自定义的结构体,那么传递的是承载这个结构体内容的所有字节;对于引用类型,变量的值是目标对象的内存地址,所以传递的这个地址(4/8 字节)的拷贝;


  • By-Reference: 传递的是变量所在的位置(Location),可能是变量在堆栈上的内存地址,或者数组元素在堆上的内存地址。所以方法不仅仅可以从这个地址读取原始参数当前的值,还可以通过填充字节到此位置改变原始的值。对于值类型,被调用方法可以将原始的值“就地”变成一个新的值;对于引用类型,方法则会原来的引用指向一个新的对象。


  • Typed reference:可以认为强类型的引用,在 By-Reference 基础上还传递参数的类型;


二、TypedReference


基于 Typed reference 的传递时通过如果这个 TypedReference 结构体实现的,从其定义可以看出它通过字段_value 保持值得引用,并利用_type 确定其类型。它定义了一系列静态方法完成一些基于 TypedReference 得基本操作,比如创建一个 TypedReference 对象,将一个 TypedReference 对象转换成 Object,获取 TypedReference 对象得目标类型等;


public struct TypedReference{    private readonly ref byte _value;
private readonly IntPtr _type;
public unsafe static object ToObject(TypedReference value); public unsafe static TypedReference MakeTypedReference(object target, FieldInfo[] flds); public static Type GetTargetType(TypedReference value); public static RuntimeTypeHandle TargetTypeToken(TypedReference value); public static void SetTypedReference(TypedReference target, object value);}
复制代码


三、三个特殊的方法


TypedReference 还涉及三个如下三个特殊方法或者函数,可能很多开源人员都没有见过:


  • __makeref:创建一个新的 TypedReference 对象;


  • __reftype:获取引用的目标类型;


  • __refvalue:获取和设置引用的值;


四、三种参数传递方式


我们通过如下这个简单的例子来演示上述的三种参数传递方式,它们分别体现在三个对应的方法上。模拟按照 Typed reference 进行参数传递的 PassByTypedReference 方法将参数类型定义为 TypedReference,它通过断言检验传递参数的类型(通过调用__reftype 方法获取),并通过调用__refvalue 修改参数的值。


PassByValue(value);Debug.Assert(value == int.MinValue);
PassByReference(ref value);Debug.Assert(value == int.MaxValue);
value = int.MinValue;PassByTypedReference(__makeref(value));Debug.Assert(value == int.MaxValue);
static void PassByValue(int v) => v = int.MaxValue;static void PassByReference(ref int v) => v = int.MaxValue;static void PassByTypedReference(TypedReference v){ Debug.Assert(__reftype(v) == typeof(int)); __refvalue(v, int) = int.MaxValue;}
复制代码


文章转载自:Artech

原文链接:https://www.cnblogs.com/artech/p/18374284/typed_reference

体验地址:http://www.jnpfsoft.com/?from=infoq

用户头像

EquatorCoco

关注

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
除了按值和引用,方法参数的第三种传递方式_技术_EquatorCoco_InfoQ写作社区