首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >c#中“`this`”和“Equivalent”的等价功能

c#中“`this`”和“Equivalent”的等价功能
EN

Stack Overflow用户
提问于 2020-04-28 19:56:21
回答 2查看 229关注 0票数 4

如果我在类中有一个函数:

代码语言:javascript
复制
/* class snipped */
private void Expect(ref Utf8JsonReader reader, JsonTokenType t)
{
    reader.Read();
    /* snip */
}

它是通过引用传递的,因为对象正在被操作,这与静态助手函数有什么不同吗:

代码语言:javascript
复制
/*static class snipped*/
static public void Expect(this Utf8JsonReader reader, JsonTokenType t)
{
    reader.Read();
    /* snip */
}

// call helper via reader.Expect(requiredToken)

当使用ref时,如果出现任何看不见的细微差别,我会问,在嵌套函数之间传递的Utf8JsonReaderMemory<T>对象的代码中,它占了很大的比重。

我期待着重构(在本例中,对reader对象使用扩展方法会更好)。

this (extension on external )和ref (通过函数之间的引用传递)功能等效吗?

ref this 更新-需要??

作为一个更新,简单地使用this不起作用,在ExpectNamedProperty函数中它将调用reader.Expect,但返回时对象将恢复。不知怎么的,堆栈上正在复制一个副本,或者正在发生什么事情。

我甚至不知道这是一个有效的组合,ref this确实有效,而this只是不修改。需要澄清,不要做可怕的事情!

代码语言:javascript
复制
public static void Expect(ref this Utf8JsonReader reader, JsonTokenType t)
{
    reader.Read(); // this mutation is never passed back to caller      
}

public static void ExpectNamedProperty(ref this Utf8JsonReader reader, string expectedPropertyName)
{
    reader.Expect(JsonTokenType.PropertyName, expectedPropertyName);

    // at this point it is as if the function above was never called

    var foundPropertyName = reader.GetString();

    if (foundPropertyName != StreamFieldNames.Event)
        throw new JsonException($"expected {StreamFieldNames.Event} found {foundPropertyName} at position {reader.Position.GetInteger()}");
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-05-01 00:41:39

ref很好。和ref this等价于/另一种形式的

ExtensionsClass.ExpectNamedProperty(参考读取器)

同时,不使用

在这种情况下,in会使性能更差。

in非常适合于readonly struct,而对于非只读结构,编译器每次使用结构来确保结构为只读时,都会创建防御复制。这大大降低了性能。

在您的例子中,Utf8JsonReader是一个ref struct,而不是readonly struct

考虑一下这个例子:

代码语言:javascript
复制
private void ExpectWithIn(in Utf8JsonReader reader)
{
    reader.Read();
}

private void ExpectWithRef(ref Utf8JsonReader reader)
{
    reader.Read();
}

ExpectWithRef(ref reader);
ExpectWithIn(reader);

ExpectWithRef编译后的IL

代码语言:javascript
复制
// (no C# code)
IL_0000: nop
// reader.Read();
IL_0001: ldarg.1
IL_0002: call instance bool [System.Text.Json]System.Text.Json.Utf8JsonReader::Read()
IL_0007: pop
// (no C# code)
IL_0008: ret

ExpectWithIn编译后的IL

代码语言:javascript
复制
// (no C# code)
IL_0000: nop

// The compiler creates defensive copy to make sure reader variable is readonly
// The compiler repeats this for every use of reader variable
// so this is significant impact 

// Utf8JsonReader utf8JsonReader = reader;
IL_0001: ldarg.1
IL_0002: ldobj [System.Text.Json]System.Text.Json.Utf8JsonReader
IL_0007: stloc.0


// utf8JsonReader.Read();
IL_0008: ldloca.s 0
IL_000a: call instance bool [System.Text.Json]System.Text.Json.Utf8JsonReader::Read()
IL_000f: pop
// (no C# code)
IL_0010: ret

Sergey有一篇好文章解释in修饰符以及何时使用它。

这意味着您永远不应该传递非只读结构作为参数。它几乎总是会使性能更差的。

票数 2
EN

Stack Overflow用户

发布于 2020-04-28 20:10:24

您可以编写许多扩展方法,但它们真的相关吗?在扩展方法中编写每件东西都会生成意大利面代码。

我会选择in关键字。inref上的优点是您无法修改参数,但是您将得不到一个副本(就像一个“正常”参数)。此外,您还可以将只读字段作为in参数传递。

代码语言:javascript
复制
private void Expect(in Utf8JsonReader reader, in JsonTokenType t)
{
   reader.Read();
    /* snip */
}
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61488887

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档