[C#]Ещё одна проблема с generics - как совместить generic и sizeof()

agaaaa

public unsafe virtual T Read<T>( ) where T:struct
{
byte* data = stackalloc byte[sizeof( T )];

BaseStream.Read( (byte[])data, 0, sizeof( T ) );
if ( invert ) for ( byte* left = data, right = data + sizeof( T ) - 1; left != right; left++, right-- )
{
byte tmp = *right;
*right = *left;
*left = tmp;
}
return *T*) data);
}

Error 6 Cannot take the address of, get the size of, or declare a pointer to a managed type ('T') D:\Coding\Projects\Lost\Lost\IO\StreamData.cs 33 49 Lost

Helga87

Marshal.SizeOf(typeof(T;
Но будет работать только, если T - value-type, очевидно.
upd. Но у тебя T - структура, так что все круто.

agaaaa

Сдаётся мне, что будет лагать
Неужели не помогут генерики?

Helga87

1. В каком смысле лагать? Давать неверный результат? Требовать большого времени на вычисление? Или что?
2. В чем генерики должны помочь?
Кстати говоря, то, что ты делаешь, можно сделать без unsafe кода, если использовать Marshal.PtrToStructure
upd. Если у тебя sizeof(T) будет четным и invert == true, ты перевернешь всю память, до какой дотянешься.

agaaaa

а) медленнее
б) вижу, исправлю

Helga87

Тогда сделай так:
public class MarshalHlp<T> where T : struct
{
static int size = Marshal.SizeOf(typeof(T;
public static T Read(Stream stream, bool invert)
{
...
}
}
В этом случае вычисление размера будет происходить один раз, в момент компиляции конкретного типа MarshalHlp, и потери скорости не будет.

agaaaa

Отличная идея!
Однако остаётся проблема с инвертированием. Меня не радует идея использования маршалинга в более-менее критичном по скорости коде. Как передать byte* вместо byte[], если это возможно?

Helga87

Однако остаётся проблема с инвертированием. Меня не радует идея использования маршалинга в более-менее критичном по скорости коде.

Не осознал, где проблема. Поясни, пожалуйста.

agaaaa

Мне показалось, что при использовании Marshal.PtrToStructure лишний раз передаются данные и вдобавок маршалер должен разбираться, как их преобразовывать. Это накладно.

Helga87

Я сейчас посмотрел, использование Marshal.PtrToStructure в два раза замедляет код. Если скорость критична, лучше действительно остаться в unsafe коде

bleyman

А вот если сделать что-нить такое:
void unsafe Invert(ref Chunk chunk)
{
fixed (Chunk * ptr = &chunk)
{
// cast to byte* and invert
}
}
Не станет ли существенно легче и быстрее?

vall

афигеть нафига этот C# нужен?
чтоб потом хитрожопо преодолевать безопасный синтаксис чтоб добится скорости такой же как на тривиальном сишном коде?

agaaaa

чтобы один раз написать хитрожопо, а потом писать КРАСИВО

agaaaa

А вот если сделать что-нить такое:
...
Не станет ли существенно легче и быстрее?

Читай тему с начала. Нужен generic метод

agaaaa

чорд! вся загвоздка в "Cannot take the address of, get the size of, or declare a pointer to a managed type ('T') "

bleyman

Йопт, и в чём проблема?
Сделай как Красин говорит - запомни размер в константу.
Насколько я понял, у тебя проблема ещё и в дополнительном копировании памяти - когда ты проинверсенную структуру возвращаешь из метода. Вот я тебе и советую - сделай функцию Invert, которой передаётся ссылка на структуру, а она её inplace инвертит. Правда, я не уверен, что это возможно - как шарп работает с ref struct я не особенно понимаю =)

bleyman

И буфер, в который считываешь фигню, тоже выдели статически.

bleyman

И нефиг возвращать структуры, это медленно!

agaaaa

Всё это замеательно, конечно. Но вот проблема: нельзя взять поинтер от преременной генерик-типа T.
Поэтому я не вижу способов скопировать в неё данные напрямую из массива. Только маршалинг. А он слишком медленный, особенно для сложных структур

bleyman

Используй макрогенератор и не парься.

vall

+1
тем-более что в C# вроде можно разбить описание класса на несколько файлов, так что гемора с этим будет немного.

Helga87

Скажи-ка, супервайзер!
Как поможет макрогенератор в случае, когда тип структуры я узнал в runtime-е?

bleyman

А что, генерики умеют инстанцироваться в рантайме? А как их потом использовать?
Неверзелесс, можно и скомпилировать кусочек кода =)

Helga87

Генерики инстанциируются именно в рантайме. Плюсы в том, что мы можем написать библиотеку, которая делает что-то, например, как у автора темы, читает из stream-а, а потом кто-то будет ее использовать, подсовывая свои типы и радуясь. Библиотека таким образом узнает о том, что в нее подсунули в runtime-е.
Скомпилировать кусочек кода - это отличная потеря времени, а главное, нереальный гемор. Ведь в случае твоего решения, у нас не будет никакой поддержки от студии при использовании этого кода.
Для автора треда наиболее правильным решением будет пользоваться Marshal.PtrToStructure. В конце концов, этот метод и предназначен для решения такой задачи.

vall

изврат.
пусть автор трэда расскажет подробнее для чего это ему нужно.
почти наверняка решение существует значительно более простое.

Helga87

изврат.

Чье именно решение ты считаешь извратом? Мое или -я?

aleks058

Вот заволновался-то.
Тваё, канешна, прогер неадекватный

Helga87

Злой ты
Аргументы тогда приведи.

agaaaa

Как правильно заметил Ваш оппонент, , требуется некий общий подход к решению проблемы. То есть надо уметь грузить произвольный структурный тип. В заголовке темы указано, что нужно совместить generics и работу с указателями.
Насколько я понял, единственным выходом является именно использование Marshal, т.к. в C# нельзя указать, что тип должен быть именно неуправляемым. Более того неуправляемыми являются только предопределённые типы данных. Надеюсь в будущем такое ограничение будет снято

vall

эээ, ты сериализацию переписываешь?

agaaaa

Кстати говоря, то, что ты делаешь, можно сделать без unsafe кода, если использовать Marshal.PtrToStructure
Не понял, как без unsafe. Где взять IntPtr?

Helga87

 
public static object GetStructure(byte [] array, int startIndex, Type type)
{
int length = Marshal.SizeOf(type);
IntPtr pointer = Marshal.AllocHGlobal(length);
Marshal.Copy(array, startIndex, pointer, length);
object result = Marshal.PtrToStructure(pointer, type);
Marshal.FreeHGlobal(pointer);
return result;
}
  

bleyman

Ыыыы...
При этом возвращается забоксенная структура и при любых попытках что-нибудь с ней сделать будет происходить unboxing и прочее копирование.
Я с самого начала говорю - если хочется превратить массив байт в структуру, то нужно передавать ссылку на то место, куда нужно засовывать результат (например, массив структур, а возможно и ref будет работать).

Helga87

Приведи полный код аналогичной функции у тебя, тогда можно будет сравнить по времени. А так - беспредметный спор.
Оставить комментарий
Имя или ник:
Комментарий: