Как заменить Marshal.SizeOf(Object) на Marshal.SizeOf‹T›()?

Я создаю библиотеку классов Universal из существующего кода и получаю некоторые предупреждения компилятора, с которыми я не могу понять, что с ними делать.

У меня есть такой код:

void SomeMethod(Object data)
{
  var size = Marshal.SizeOf(data);
  ...
}

Код собирается, но в проекте Universal (и, я думаю, в проектах .NET 4.5.1 и выше) я получаю следующее предупреждение компилятора:

предупреждение CS0618: «System.Runtime.InteropServices.Marshal.SizeOf(object)» устарело: «SizeOf(Object) может быть недоступен в будущих выпусках. Вместо этого используйте SizeOf‹T›().

Но как мне создать замену для Marshal.SizeOf(Object) в приведенном выше случае, используя общий метод без параметров Marshal.SizeOf<T>()? Теоретически я могу не знать, что такое тип data?

Это потому, что использование Marshal.SizeOf(Object) считается плохой практикой, поэтому ему приписывают Obsolete? И сообщение на вынос действительно должно быть «полный рефакторинг кода»?


person Anders Gustafsson    schedule 24.10.2014    source источник
comment
Это, конечно, не устарело в 4.5.1. Я предполагаю, что он устарел именно в универсальной эталонной сборке, потому что это головная боль для опережающего компилятора .NET Native. Непонятно, почему нельзя просто сделать SomeMethod универсальным. Если вы не можете этого сделать, у цепочки инструментов .NET Native также могут возникнуть проблемы.   -  person Hans Passant    schedule 25.10.2014
comment
Я удалил свой ответ. См. SizeOf‹T›(T) в MSDN. Он принимает <T>, а также параметр. Вы можете передать туда свой объект, и он будет правильно измерен. Я почти уверен, что вы сможете успешно пройти даже Marhal.SizeOf<object>(data). Престижность NemanjaBoric за указание на это. Я не пишу ответ с этим, так как я не могу проверить (сейчас у меня нет компилятора 4.5.1), действительно ли он работает, но я не понимаю, почему бы и нет, поскольку он принимает конечный объект и может читать его настоящий Тип.   -  person quetzalcoatl    schedule 25.10.2014
comment
Спасибо за вашу помощь, @quetzalcoatl и NemanjaBoric. Глупо с моей стороны пропустить эту SizeOf перегрузку. Я попробую и посмотрю, насколько хорошо он соответствует моим потребностям.   -  person Anders Gustafsson    schedule 26.10.2014


Ответы (1)


Хорошо, после ваших комментариев кажется, что все, что вам нужно, уже есть:

SizeOf<T>(T): я думаю, что это метод, который вам нужен, но вам не нужно явно определять общий параметр из-за вывод типа. Вы просто пишете var size = Marshal.SizeOf(myStructure);, и компилятор извлекает тип из данного объекта и заполняет общий параметр.

SizeOf<T>(): этот метод входит в удобно, когда ваш собственный класс, возможно, уже является универсальным классом, и у вас есть T, но нет реального экземпляра используемого универсального типа. В этом случае следует выбрать этот метод.

Как насчет этого подхода к отражению:

private static int MySizeOf(object structure)
{
    var marshalType = typeof(Marshal);
    var genericSizeOfMethod = marshalType.GetMethod("SizeOf", Type.EmptyTypes);
    var sizeOfMethod = genericSizeOfMethod.MakeGenericMethod(structure.GetType());
    var size = (int)sizeOfMethod.Invoke(null, null);

    return size;
}

person Oliver    schedule 28.10.2014
comment
Интересная мысль, хотя мне не совсем удобно вводить метод, основанный на отражении, для решения этой проблемы. Я также думаю, что ваш код может потребовать некоторой адаптации: (1) я не думаю, что Type.GetMethod доступен в универсальных проектах, вам может потребоваться пройти TypeInfo.DeclaredMethods, чтобы получить перегрузки SizeOf; (2) Я думаю, вы упускаете возможность передать объект structure в метод, может быть, второй аргумент в вызове Invoke должен быть new[] { structure } вместо null? - person Anders Gustafsson; 28.10.2014
comment
Никогда не работал с универсалами, поэтому не знаю их ограничений. Для вызова Invoke вам не нужно передавать структуру, потому что мы уже извлекли тип и использовали его для общего вызова Marshal.SizeOf<StructureType>(). - person Oliver; 28.10.2014
comment
Но всегда ли неуправляемый размер объекта structure одинаков? Тогда почему существуют две перегрузки Marshal.SizeOf<T>, Marshal.SizeOf<T>() и Marshal.SizeOf<T>(T), в 4.5.1 и более поздние версии? И я совершенно уверен, что вы не можете сделать Type.GetMethod в универсальном проекте, поскольку этот метод недоступен для современных приложений Windows (например, Metro). - person Anders Gustafsson; 28.10.2014
comment
Спасибо, Оливер. В принципе, вывод типа должен помочь, да, но он запутывается из-за перегрузки приоритета; Marshal.SizeOf(object) имеет приоритет над Marshal.SizeOf<T>(T), поэтому я в первую очередь получаю предупреждающее сообщение. Я еще не пробовал последствия использования перегрузки Marshal.SizeOf<T>(T), но когда я это сделаю, я сообщу о результате. - person Anders Gustafsson; 29.10.2014