Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用in参数直接调用带有ref参数的方法_C#_Ref_C# 7.2 - Fatal编程技术网

C# 如何使用in参数直接调用带有ref参数的方法

C# 如何使用in参数直接调用带有ref参数的方法,c#,ref,c#-7.2,C#,Ref,C# 7.2,我使用的是一个遗留库中的方法:F(ref T),其中T:struct。它被声明为ref,仅出于性能原因,不修改它接收的数据。此库不能更改 在我的代码中,我有一个新方法G(在T中),其中T:struct调用F 有没有一种方法可以直接用我收到的引用调用F,而无需先将其复制到临时引用?我刚刚读到了“in”。显然,in、ref和out都是一种通过引用调用的形式。然而,主要区别在于“他们的意向声明” 无法修改参数中的。它们只是出于性能原因(如果有的话)参考存在 ref参数可以修改,也可以不修改。这是最接近

我使用的是一个遗留库中的方法:
F(ref T),其中T:struct
。它被声明为
ref
,仅出于性能原因,不修改它接收的数据。此库不能更改

在我的代码中,我有一个新方法
G(在T中),其中T:struct
调用
F

有没有一种方法可以直接用我收到的引用调用
F
,而无需先将其复制到临时引用?

我刚刚读到了“in”。显然,in、ref和out都是一种通过引用调用的形式。然而,主要区别在于“他们的意向声明”

无法修改参数中的
。它们只是出于性能原因(如果有的话)参考存在

ref
参数可以修改,也可以不修改。这是最接近经典的“引用调用”。实际上,当您通过裸指针实现它时,这是唯一的方法

out
参数需要修改;如果一个值需要初始化(如构造函数中的只读),这可能是相关的-如果它作为输出变量提交,编译器可以放心它将被设置。其他函数编译器确保了这一点

在某种程度上,
中的
是一种“ref,但只读”。无法将收到的内容作为“in”分配给“ref”或“out”,并阻止您意外更改该值。我猜你也不会在那里使用ref(这可能会使它毫无意义)或进行复制。

是的,有一种方法(但它使用了不安全的黑魔法)

首先是免责声明

方法
F
不修改
struct
只是您的“约定”。对于C#编译器,
ref
提供的
struct
是完全可变的

通过
中的via
提供一个由
readonly ref提供的
struct
告诉编译器:请确保这个
struct
不能被变异

顺便说一下,如果您在中将
结构
作为
传递,则必须确保该
结构
声明为
只读结构
。否则,编译器将创建
struct
的防御性副本(详细信息请阅读)。这是通常无法将
readonly struct
引用传递给通过
ref
接受
struct
并对其进行变异的方法的第二个原因

如果您仍然想绕过所有这些限制,那么可以使用NuGet包

Unsafe
静态类中有一个方法可以帮助您:

public static ref T AsRef<T>(in T source);
公共静态ref T AsRef(在T源中);
以下是一个例子:

void F<T>(ref T t) where T : struct
{
}

void G<T>(in T t) where T : struct
{
    F(ref System.Runtime.CompilerServices.Unsafe.AsRef(in t));
}
void F(参考T),其中T:struct
{
}
void G(在T中),其中T:struct
{
F(ref System.Runtime.CompilerServices.Unsafe.AsRef(在t中));
}

方法是使您的函数也成为ref函数。然后,您只需一路传递引用。In、ref和out的意图声明不同:“in关键字导致参数通过引用传递。它类似于ref或out关键字,只是in参数不能被调用的方法修改。尽管可以修改ref参数,但out参数必须由被调用的方法修改,并且这些修改在调用上下文中是可见的。“在这一点上,我们一直都是正确的工具。但是如果没有这些,你可能也需要使用ref。编译器不允许您在ref参数点上放置in aragument,这正是in存在的原因。很抱歉,这是一个通用的答案,没有太大帮助。我知道关键字的作用。我正在寻找一种绕过正常操作的方法,希望通过一些巧妙的类型转换或类似的方法,而不是使用Emit来实现(这就是我目前正在做的)。我将查看包,谢谢。但是,这是不正确的:“无法将只读结构引用传递给接受struct by ref的方法”。您完全可以这样做,而且不需要防御性副本,因为您不能在
ref t
方法中实际修改它,因为它是只读的。@chase,不满意的措辞,精练的。我的意思是:如果您通过
中的
获取它,那么它可能是
只读的
,因此将它传递给接受
引用的方法可能是危险的,因为该方法可能会变异
结构
。这确实是一个非常有用的包。使用
AsRef
的性能似乎与直接调用相同。还有,不要再发射了,耶!我想我的“不能真正修改它”也可以使用免责声明:不是通过常规方式。不安全、反射等等,所有这些都会从窗口消失,正如这个包奇妙地演示的;)