Как напрямую вызвать метод с параметром ref, используя параметр
Я использую метод из устаревшей библиотеки: F (ref T t) where T: struct
, Это объявлено как ref
только из соображений производительности и не изменяет данные, которые он получает. Эта библиотека не может быть изменена.
В моем коде у меня есть новый метод G (in T t) where T: struct
что вызывает F
,
Есть ли способ позвонить F
напрямую со ссылкой, которую я получаю, не копируя ее во временную папку?
2 ответа
Да, есть способ (но он использует небезопасную черную магию).
Сначала отказ от ответственности.
Тот факт, что метод F
не изменяет struct
это только твоя "конвенция". Для компилятора C# struct
предоставлено ref
совершенно изменчив.
Иметь struct
предоставлено readonly ref
с помощью in
говорит компилятору: пожалуйста, убедитесь, что это struct
не может быть мутирован.
Кстати, если вы передаете struct
как in
, вы должны убедиться, что это struct
объявлен как readonly struct
, В противном случае компилятор создаст защитные копии struct
(подробности читайте здесь.) Это вторая причина, по которой вы обычно не можете пройти readonly struct
ссылка на метод, принимающий struct
от ref
и мутируя это.
Если вы все еще хотите обойти все эти ограничения, вы можете использовать System.Runtime.CompilerServices.Unsafe
Пакет NuGet.
В методе есть Unsafe
статический класс, который может помочь вам:
public static ref T AsRef<T>(in T source);
Вот пример:
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));
}
Я только что прочитал "в". По-видимому, оба, ref и out являются формой вызова по ссылке. Однако основное отличие заключается в "их заявлении о намерениях".
in
аргументы не могут быть изменены. Они есть только для справки, если это вообще делается.
ref
аргументы могут или не могут быть изменены. Это наиболее близкий к классическому "звонок по ссылке". На самом деле, это единственный способ, которым вы пользуетесь, используя голые указатели.
out
аргументы должны быть изменены; это может иметь значение, если значение требует инициализации (например, только для чтения в конструкторе) - если оно передается как переменная out, компилятор может быть уверен, что оно будет установлено. Компилятор других функций убедился в этом.
В пути in
это своего рода "ссылка, но только для чтения". Невозможность назначить что-то, что вы получили как "in", на "ref" или "out", а также заблокировать вас от случайного изменения значения. Я полагаю, что вы не сможете обойтись ни с использованием ссылки там (которая делает это возможно бессмысленной), ни с копированием.