6

I am building a Universal class library from existing code, and I get some compiler warnings that I for the life of it cannot figure out what to do with.

I have code like this:

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

The code builds, but in the Universal project (and, I guess, .NET 4.5.1 and higher projects) I get the following compiler warning:

warning CS0618: 'System.Runtime.InteropServices.Marshal.SizeOf(object)' is obsolete: 'SizeOf(Object) may be unavailable in future releases. Instead, use SizeOf<T>().

But how do I create a replacement for Marshal.SizeOf(Object) in the above case using the generic parameter-less method Marshal.SizeOf<T>()? Theoretically, I might not have any idea what type data is?

Is it because using Marshal.SizeOf(Object) is considered bad practice that it has been attributed Obsolete? And the take-home message should really be "refactor the code completely"?

Anders Gustafsson
  • 15,837
  • 8
  • 56
  • 114
  • 3
    It certainly isn't obsolete in 4.5.1. I'm guessing that it was made obsolete specifically in the Universal reference assembly because it is a pain in the neck for .NET Native ahead-of-time compiler. It is not clear why you couldn't just make SomeMethod generic. If you can't then the .NET Native toolchain is liable to have trouble as well. – Hans Passant Oct 24 '14 at 20:57
  • 1
    I have removed my answer. Please see [SizeOf(T) on MSDN](http://msdn.microsoft.com/en-us/library/vstudio/dn261467(v=vs.110).aspx). It takes `` and also a parameter. You can pass your object there, and it will be measured properly. I'm pretty sure you should be able to even successfully pass `Marhal.SizeOf(data)`. Kudos to NemanjaBoric for pointing this out. I'm not writing an answer with that, since I cannot verify (I dont have 4.5.1 compiler now) if it really works, but I don't see why shouldn't it as it takes final object and it can read it's real Type. – quetzalcoatl Oct 24 '14 at 21:07
  • Thanks for all your help, @quetzalcoatl and NemanjaBoric. Silly of me to miss that `SizeOf` overload. I will give it a try and see how well it fits my needs. – Anders Gustafsson Oct 25 '14 at 21:30

1 Answers1

0

Okay, after getting your comments it seems that everything you need is already there:

SizeOf<T>(T): I think this is the method you need, but you don't have to define the generic parameter explictly, due to type inference. You simple write var size = Marshal.SizeOf(myStructure); and the compiler will extract the type from the given object and fill out the generic parameter.

SizeOf<T>(): This method comes in handy when your own class is maybe already a generic class and you have a T but no real instance of the used generic type. In that case this method should be choosen.

How about this reflection approach:

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;
}

Oliver
  • 43,366
  • 8
  • 94
  • 151
  • 1
    Interesting thought, although I am not entirely comfortable with introducing a reflection relying method to solve this problem. I also think your code might require some adaptation: (1) I do not think `Type.GetMethod` is available in Universal projects, you might need to traverse `TypeInfo.DeclaredMethods` to obtain the `SizeOf` overloads; (2) I think you are missing the opportunity to pass the `structure` object to the method, maybe the second argument in the `Invoke` call should be `new[] { structure }` instead of null? – Anders Gustafsson Oct 28 '14 at 13:56
  • Never worked with Universals, so i don't know their restrictions. For the Invoke call you don't need to pass the structure, cause we already extracted the type and used that for the generic call `Marshal.SizeOf()`. – Oliver Oct 28 '14 at 15:15
  • But is the unmanaged size of the `structure` object always the same? Then, why are there two `Marshal.SizeOf` overloads, `Marshal.SizeOf()` and `Marshal.SizeOf(T)`, in [the 4.5.1 and later frameworks](http://msdn.microsoft.com/en-us/library/vstudio/system.runtime.interopservices.marshal.sizeof(v=vs.110).aspx)? And, I am fairly sure that you can't do `Type.GetMethod` in a Universal project, since the method is not available for modern Windows (f.k.a. Metro) apps. – Anders Gustafsson Oct 28 '14 at 15:21
  • Thanks, Oliver. In principle, type inference should do the trick, yes, but it is obfuscated by overloading precedence; `Marshal.SizeOf(object)` takes precedence over `Marshal.SizeOf(T)`, which is why I get the warning message in the first place. I have not gotten to try the implications of using the `Marshal.SizeOf(T)` overload yet, but when I've done that I will report the result. – Anders Gustafsson Oct 29 '14 at 08:03