Выделение универсальных типов.NET

Вот программа на C#, которая пытается Marshal.SizeOf на несколько разных типов:

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
class AClass { }

[StructLayout(LayoutKind.Sequential)] 
struct AStruct { }

[StructLayout(LayoutKind.Sequential)]
class B { AClass value; }

[StructLayout(LayoutKind.Sequential)]
class C<T> { T value; }

class Program
{
    static void M(object o) { Console.WriteLine(Marshal.SizeOf(o)); }

    static void Main()
    {
        M(new AClass());
        M(new AStruct());
        M(new B());
        M(new C<AStruct>());
        M(new C<AClass>());
    }
}

Первые четыре вызова M() завершаются успешно, но при последнем вызове SizeOf генерирует ArgumentException:

"Type 'C`1[AClass]' cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed."

Зачем? В частности, почему SizeOf подавляется C<AClass>, но не на B или на C<AStruct>?


РЕДАКТИРОВАТЬ: Поскольку это было задано в комментариях, вот проблема "реального мира", которая вдохновила этот в основном академический вопрос: я обращаюсь к C API, который в основном является одной из функций C, которая работает (указывает на) много различные типы простых C-структур. Все они содержат общий заголовок, за которым следует одно поле, но тип этого поля отличается в разных структурах. Флаг в заголовке указывает тип поля. (Странно, да, но это то, с чем я должен работать).

Если бы я мог определить один общий тип C<T> и единственное объявление C# extern M(C<T>), а затем позвоните M(C<int>) на одной строке и M(C<double>) с другой, у меня было бы короткое и приятное решение для взаимодействия. Но, учитывая ответ JaredPar, кажется, что я должен сделать отдельный тип C# для каждой структуры (хотя наследование может обеспечить общий заголовок).

2 ответа

Решение

Обобщения, как правило, не поддерживаются ни в одном сценарии взаимодействия. И P/Invoke, и COM Interop потерпят неудачу, если вы попытаетесь упорядочить универсальный тип или значение. Следовательно, я ожидал бы, что Marshal.SizeOf будет непроверенным или неподдерживаемым для этого сценария, поскольку это специфическая для маршала функция.

Неизвестно, какой размер будет иметь агрегированный объект T (это будет размер указателя, если T является ссылочным типом, и в основном любое значение, если это тип значения).

Я думаю, что вы можете решить эту проблему, установив атрибут MarshalAs в поле 'value', указав наиболее подходящий тип (например, Unmanagedtype.SysInt). Обратите внимание, что он все равно не будет работать для так называемых не отображаемых типов (т. Е. Типов, для которых смещения и размеры полей не могут быть легко определены).

Но AFAIK, не рекомендуется использовать дженерики во взаимодействии.

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