如果我在类中有一个函数:
/* class snipped */
private void Expect(ref Utf8JsonReader reader, JsonTokenType t)
{
reader.Read();
/* snip */
}它是通过引用传递的,因为对象正在被操作,这与静态助手函数有什么不同吗:
/*static class snipped*/
static public void Expect(this Utf8JsonReader reader, JsonTokenType t)
{
reader.Read();
/* snip */
}
// call helper via reader.Expect(requiredToken)当使用ref时,如果出现任何看不见的细微差别,我会问,在嵌套函数之间传递的Utf8JsonReader和Memory<T>对象的代码中,它占了很大的比重。
我期待着重构(在本例中,对reader对象使用扩展方法会更好)。
this (extension on external )和ref (通过函数之间的引用传递)功能等效吗?
ref this 更新-需要??
作为一个更新,简单地使用this不起作用,在ExpectNamedProperty函数中它将调用reader.Expect,但返回时对象将恢复。不知怎么的,堆栈上正在复制一个副本,或者正在发生什么事情。
我甚至不知道这是一个有效的组合,ref this确实有效,而this只是不修改。需要澄清,不要做可怕的事情!
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()}");
}发布于 2020-05-01 00:41:39
ref很好。和ref this等价于/另一种形式的
ExtensionsClass.ExpectNamedProperty(参考读取器)
同时,不使用
在这种情况下,in会使性能更差。
in非常适合于readonly struct,而对于非只读结构,编译器每次使用结构来确保结构为只读时,都会创建防御复制。这大大降低了性能。
在您的例子中,Utf8JsonReader是一个ref struct,而不是readonly struct。
考虑一下这个例子:
private void ExpectWithIn(in Utf8JsonReader reader)
{
reader.Read();
}
private void ExpectWithRef(ref Utf8JsonReader reader)
{
reader.Read();
}
ExpectWithRef(ref reader);
ExpectWithIn(reader);ExpectWithRef编译后的IL
// (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: retExpectWithIn编译后的IL
// (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: retSergey有一篇好文章解释in修饰符以及何时使用它。
这意味着您永远不应该传递非只读结构作为参数。它几乎总是会使性能更差的。
发布于 2020-04-28 20:10:24
您可以编写许多扩展方法,但它们真的相关吗?在扩展方法中编写每件东西都会生成意大利面代码。
我会选择in关键字。in在ref上的优点是您无法修改参数,但是您将得不到一个副本(就像一个“正常”参数)。此外,您还可以将只读字段作为in参数传递。
private void Expect(in Utf8JsonReader reader, in JsonTokenType t)
{
reader.Read();
/* snip */
}https://stackoverflow.com/questions/61488887
复制相似问题