C#:在运行时获取值类型变量的大小?

我知道C和C ++等语言允许在运行时使用sizeof()函数确定数据的大小(结构,数组,变量……)。 我在C#中尝试过,显然它不允许将变量放入sizeof()函数,但只键入defintions(float,byte,Int32,uint等等),我该怎么做呢?

实际上,我希望这种情况发生:

int x; Console.WriteLine(sizeof(x)); // Output: 4 

并不是:

 Console.WriteLine(sizeof(int)); // Output: 4 

我确信在C#中有一些正常的方法可以在运行时获取数据大小,但谷歌并没有提供太多帮助..这是我最后的希望

要在运行时查找任意变量x的大小,您可以使用Marshal.SizeOf :

 System.Runtime.InteropServices.Marshal.SizeOf(x) 

正如dtb所提到的,这个函数在编组后返回变量的大小,但根据我的经验,这通常是你想要的大小,就像在纯托管环境中一样,变量的大小没什么意义。

继Cory的回答之后 ,如果性能很重要且你需要经常使用这段代码,那么你可以缓存大小,这样动态方法只需要为每种类型构建和执行一次:

 int x = 42; Console.WriteLine(Utils.SizeOf(x)); // Output: 4 // ... public static class Utils { public static int SizeOf(T obj) { return SizeOfCache.SizeOf; } private static class SizeOfCache { public static readonly int SizeOf; static SizeOfCache() { var dm = new DynamicMethod("func", typeof(int), Type.EmptyTypes, typeof(Utils)); ILGenerator il = dm.GetILGenerator(); il.Emit(OpCodes.Sizeof, typeof(T)); il.Emit(OpCodes.Ret); var func = (Func)dm.CreateDelegate(typeof(Func)); SizeOf = func(); } } } 

int的大小总是32位。 为什么你需要在运行时获得大小?

话虽如此,您可以使用Marshal.SizeOf() ,但这仅适用于非托管代码。

我偶然发现了一些显然会给你一个值类型大小的代码 。 它使用reflection,与您想要使用的function( sizeof() )相比,这是一个非常昂贵的方法调用:

 using System; using System.Reflection; using System.Reflection.Emit; ... // GetManagedSize() returns the size of a structure whose type // is 'type', as stored in managed memory. For any referenec type // this will simply return the size of a pointer (4 or 8). public static int GetManagedSize(Type type) { // all this just to invoke one opcode with no arguments! var method = new DynamicMethod("GetManagedSizeImpl", typeof(uint), new Type[0], typeof(TypeExtensions), false); ILGenerator gen = method.GetILGenerator(); gen.Emit(OpCodes.Sizeof, type); gen.Emit(OpCodes.Ret); var func = (Func)method.CreateDelegate(typeof(Func)); return checked((int)func()); } 

我打算说使用类型推断来满足你的要求(“如果你改变x的类型从int改为long long,你不必用sizeof(long long)替换sizeof(int)的每一次出现”) :

 public unsafe void GetSizeOf(T exemplar) where T : struct { return sizeof(T); } 

但是你不能这样做,因为T可能是一个“托管类型” – 它可能是一个带有对象引用字段的结构。 似乎没有办法将T限制为仅非托管类型。

您可以使用静态助手类:

 public static class Size { public int Of(int x) { return sizeof(int); } public int Of(long x) { return sizeof(long); } public unsafe int Of(MyStruct x) { //only works if MyStruct is unmanaged return sizeof(MyStruct); } } public class Program { public void Main() { int x = 0; Console.WriteLine(Size.Of(x)); } public void OldMain() { long x = 0; Console.WriteLine(Size.Of(x)); } } 

如果您正在执行类似构建数据包以发送到设备的操作,请尝试以下操作:

 byte[] dataBytes = BitConverter.GetBytes(x); int dataLength= dataBytes.Length; 

现在,您可以将dataBytes数组复制到dataPacket数组的Payload部分,dataLength将告诉您要复制的字节数,并让您validation或设置数据包中的PayloadLength值。

前进并为CORY发布的代码添加了一些安全/性能/便利function,因为较少偏执的LukeH代码应该足够了。

简而言之,这个类返回类型大小,确保尽可能使用缓存,从外部类中包含exception。

您可能希望重写catch-all块以更好地适应您的项目。

 /* A class for finding the sizes of types and variables */ public static class Sizes { /* Retrieves the size of the generic type T Returns the size of 'T' on success, 0 otherwise */ public static int SizeOf() { return FetchSizeOf(typeof(T)); } /* Retrieves the size of the type of obj Returns the size of 'obj' on success, 0 otherwise */ public static int SizeOf(T obj) { return FetchSizeOf(typeof(T)); } /* Retrieves the size of 'type' Returns the size of 'type' on success, 0 otherwise */ public static int SizeOf(this Type type) { return FetchSizeOf(type); } /* Gets the size of the specified type Returns the size of 'type' on success, 0 otherwise*/ private static int FetchSizeOf(this Type type) { if ( typeSizeCache == null ) CreateCache(); if ( typeSizeCache != null ) { int size = 0; if ( GetCachedSizeOf(type, out size) ) return size; else return CalcAndCacheSizeOf(type); } else return CalcSizeOf(type); } /* Attempts to get the size of type from the cache Returns true and sets size on success, returns false and sets size to 0 otherwise. */ private static bool GetCachedSizeOf(Type type, out int size) { size = 0; try { if ( type != null ) { if ( !typeSizeCache.TryGetValue(type, out size) ) size = 0; } } catch { /* - Documented: ArgumentNullException - No critical exceptions. */ size = 0; } return size > 0; } /* Attempts to calculate the size of 'type', and caches the size if it is valid (size > 0) Returns the calclated size on success, 0 otherwise */ private static int CalcAndCacheSizeOf(Type type) { int typeSize = 0; try { typeSize = CalcSizeOf(type); if ( typeSize > 0 ) typeSizeCache.Add(type, typeSize); } catch { /* - Documented: ArgumentException, ArgumentNullException, - Additionally Expected: OutOfMemoryException - No critical exceptions documented. */ } return typeSize; } /* Calculates the size of a type using dynamic methods Return the type's size on success, 0 otherwise */ private static int CalcSizeOf(this Type type) { try { var sizeOfMethod = new DynamicMethod("SizeOf", typeof(int), Type.EmptyTypes); var generator = sizeOfMethod.GetILGenerator(); generator.Emit(OpCodes.Sizeof, type); generator.Emit(OpCodes.Ret); var sizeFunction = (Func)sizeOfMethod.CreateDelegate(typeof(Func)); return sizeFunction(); } catch { /* - Documented: OutOfMemoryException, ArgumentNullException, ArgumentException, MissingMethodException, MethodAccessException - No critical exceptions documented. */ } return 0; } /* Attempts to allocate the typeSizesCache returns whether the cache is allocated*/ private static bool CreateCache() { if ( typeSizeCache == null ) { try { typeSizeCache = new Dictionary(); } catch { /* - Documented: OutOfMemoryException - No critical exceptions documented. */ typeSizeCache = null; } } return typeSizeCache != null; } /* Static constructor for Sizes, sets typeSizeCache to null */ static Sizes() { CreateCache(); } /* Caches the calculated size of various types */ private static Dictionary typeSizeCache; } 
 public static class TypeSize { public static int GetSize(this T value) { if (typeof(T).IsArray) { var elementSize = GetTypeSize(typeof(T).GetElementType()); var length = (value as Array)?.GetLength(0); return length.GetValueOrDefault(0) * elementSize; } return GetTypeSize(typeof(T)); } static ConcurrentDictionary _cache = new ConcurrentDictionary(); static int GetTypeSize(Type type) { return _cache.GetOrAdd(type, _ => { var dm = new DynamicMethod("SizeOfType", typeof(int), new Type[] { }); ILGenerator il = dm.GetILGenerator(); il.Emit(OpCodes.Sizeof, _); il.Emit(OpCodes.Ret); return (int)dm.Invoke(null, null); }); } }