Как напрямую вызвать метод с параметром 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", а также заблокировать вас от случайного изменения значения. Я полагаю, что вы не сможете обойтись ни с использованием ссылки там (которая делает это возможно бессмысленной), ни с копированием.

Другие вопросы по тегам