В чем смысл модификатора in для классов
в C# 7.2 вводит in
модификатор для параметров, который имеет смысл для структур и, в частности, для структур только для чтения.
также разрешено использовать его для ссылочного типа
void Method(in StringBuilder value) { }
как ссылочные типы передаются по ссылке по умолчанию, является in
в приведенном выше примере просто избыточный модификатор?
value = null
запрещено при использовании in
, означает ли это, что он щадит также копию ссылочного адреса, просто передача исходной ссылки на местоположение кучи и блокирование изменений?
3 ответов
in
компилируется в IL точно так же, как ref
, за исключением in
аргумент помечен как .
что означает in
ведет себя точно так же, как ref
, но компилятор (не среда выполнения) обеспечивает, чтобы вы не присваивали значение
из того, что я понимаю из официальная документация, это означает, что аргументы, переданные методу не будут изменены внутри самого метода:
на
in
ключевое слово указывает, что вы передаете параметр по ссылке и вызываемый метод не изменяет переданное ему значение.
при использовании in
ключевое слово с типами значений, это означает, что вместо передачи аргумента значение (то есть создание новой копии значения), оно передается по ссылке - так оно избегает ненужного копирования.
в то время как два других ответа верны, что in
параметры заканчиваются как ref
параметры в результирующем IL следует соблюдать осторожность с утверждением, что это предотвращает копирование значения. Это справедливо только для структур readonly.
чтобы продемонстрировать это, рассмотрим следующий фрагмент кода:
using System;
public struct S1
{
public int A;
public void ChangeA(int a) => A = a;
}
public static class Program
{
static void Main()
{
var s1 = new S1 { A = 1 };
S1Foo(in s1);
Console.WriteLine(s1.A);
}
private static void S1Foo(in S1 s) => s.ChangeA(2);
}
так как мы проезжаем s1
по ссылке можно разумно предположить, что S1Foo
при использовании ChangeA
затем изменит содержимое s1
. этого не происходит, хотя. Причина в том, что s1
значение копируется и копия передается по ссылке, чтобы предотвратить такие изменения структур через in
параметры.
если мы декомпилируем результирующий IL, вы видите, что код заканчивается как:
public static class Program
{
private static void Main()
{
S1 s = default(S1);
s.A = 1;
S1 s2 = s;
Program.S1Foo(ref s2);
Console.WriteLine(s2.A);
}
private static void S1Foo([IsReadOnly] [In] ref S1 s)
{
S1 s2 = s;
s2.ChangeA(2);
}
}
однако, если мы напишем аналогичный код, используя readonly struct
, то никакое копирование не происходит. Я говорю подобное, поскольку невозможно написать тот же код, что и поля и свойство должно быть прочитано только в структуре readonly (ключ находится в имени):
using System;
public readonly struct S2
{
private readonly int _a;
public int A => _a;
public S2(int a) => _a = a;
public void ChangeA(int a) { }
}
public static class Program
{
static void Main()
{
var s2 = new S2(1);
S2Foo(in s2);
Console.WriteLine(s2.A);
}
private static void S2Foo(in S2 s) => s.ChangeA(2);
}
затем в результирующем IL.
таким образом:
-
in
эффективноreadonly ref
, - значение (или ссылка) передается по ссылке,
- компилятор предотвращает изменение полей и свойств этой ссылки, чтобы помочь обеспечить ее только для чтения,
- для дальнейшего исполнения только для чтения характер параметра, а затем структуры не только для чтения копируются перед передачей ссылки на копию в метод. Это не происходит для структур readonly.