Требуется обходной путь для доступа к ReadOnlySpan внутри функции, которая возвращает IEnumerableC#

Место общения программистов C#
Ответить
Anonymous
 Требуется обходной путь для доступа к ReadOnlySpan внутри функции, которая возвращает IEnumerable

Сообщение Anonymous »

Разбираясь с совместимостью собственного кода, я решил, что пришло время изучить и опробовать новые возможности Span языка C#.
Хотя во многих испытаниях все шло отлично, пока я не подошел к заключительному этапу моей очень длинной функции, для которой я вставляю ниже лишь минимальный воспроизводимый образец:
[DllImport(dll, SetLastError = true)]
internal static extern void GetNativeData(out byte lpBuffer, int size, out bytesRead);

ReadOnlySpan ReadArray(ReadOnlySpan buf, int Length) where T : unmanaged
{
var size = Length * Unsafe.SizeOf();
if (buf.Length < size)
buf = new byte[size];
GetNativeData(out MemoryMarshal.GetReference(buf), size, out int read));
Dh.CreateError(ReadMemoryErr);

return MemoryMarshal.Cast(buf.Slice(0, size));
}

static IEnumerable GetResult()
{
// Here I allocate a buffer
Span buf = new byte[1000];

// After a long serie of calls to unmanaged DLL functions I end up with something like this:
ReadOnlySpan uintRes = data.ReadArray(buf, 10);
ReadOnlySpan shortRes = data.ReadArray(buf, 10);
for (int i = 0; i < uintRes.Length; i++)
{
// Any access to spans inside this loop result in Error CS4013
string r = GetFunRes(uintRes);
IntPtr r2 = GetFunRes2(shortRes);
yield return new MyClass() { Prop1 = r, Prop2 = r2 };
}
}

Я получаю следующую ошибку:

Ошибка CS4013: экземпляр типа «Span» нельзя использовать внутри
вложенной функции, выражения запроса, блока итератора или асинхронного метода

Я прочитал, что для этой проблемы существуют обходные пути. В статьях показано только использование асинхронных методов, но также указано, что это применимо и к итераторам. К сожалению, мне не удалось выполнить эту работу. Мне нужно только прочитать определенные элементы диапазона, а затем получить результат, который не содержит никаких элементов или ссылок на диапазон. Просто, что бы я ни пытался сделать, как только я пытаюсь получить к чему-то доступ, компилятор терпит неудачу.
Я читал о Memory, и, возможно, этот вариант может работать, но у меня есть некоторые опасения, поскольку я читал, что производительность резко снижается. Люди также рекомендуют Span в первую очередь. Надеюсь, я смогу найти решение, потому что в противном случае мне придется перезапускать свой проект с нуля и все переписывать, потому что теперь он жестко привязан к Span.

@00110001:


var uintRes = data.ReadArray(buf, 10).ToArray();


Я знаю, что это сработает, но полагаю, что это сделает бесполезным использование Span вместе с новыми неуправляемыми функциями универсальных функций, которыми я пытаюсь воспользоваться (ReadArray). Если я не ошибаюсь, вызов ToArray() аналогичен старому стилю маршалинга, когда для каждого вызова создается новая копия:


internal static extern void GetNativeData(out uint[] lpBuffer, int size, out bytesRead);


@Ian Kemp
Вот как я попробовал обходной путь, упомянутый в статье:

int len = uintRes.Length;
for (int i = 0; i < len; i++)
{
var res = ParseData(i);
if (res == ExpectedResult())
yield return res;
}
MyClass ParseData(int index)
{
// CS8175: Cannot use ref local 'uintRes, shortRes' inside an anonymous method, lambda expression, or query expression
string r = GetFunRes(uintRes[index]);
IntPtr r2 = GetFunRes2(shortRes[index]);
return new MyClass() { Prop1 = r, Prop2 = r2 };
}


Подробнее здесь: https://stackoverflow.com/questions/663 ... urns-an-ie
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»