我知道C和C ++等语言允许在运行时使用sizeof()函数确定数据的大小(结构,数组,变量......)。我在C#中尝试过,显然它不允许将变量放入sizeof()函数,但只输入defintions(float,byte,Int32,uint等等),我该怎么做?
实际上,我希望这种情况发生:
int x;
Console.WriteLine(sizeof(x)); // Output: 4
AND NOT:
Console.WriteLine(sizeof(int)); // Output: 4
我确信在C#中有一些正常的方法可以在运行时获取数据大小,但谷歌没有提供太多帮助..这是我最后的希望
答案 0 :(得分:23)
要查找任意变量的大小x
,您可以在运行时使用Marshal.SizeOf:
System.Runtime.InteropServices.Marshal.SizeOf(x)
正如dtb所提到的,这个函数在编组后返回变量的大小,但根据我的经验,这通常是你想要的大小,就像在纯托管环境中一样,变量的大小是兴趣不大。
答案 1 :(得分:20)
从Cory's answer开始,如果性能很重要并且你需要经常使用这段代码,那么你可以缓存大小,这样动态方法只需要为每个类型构建和执行一次:
int x = 42;
Console.WriteLine(Utils.SizeOf(x)); // Output: 4
// ...
public static class Utils
{
public static int SizeOf<T>(T obj)
{
return SizeOfCache<T>.SizeOf;
}
private static class SizeOfCache<T>
{
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<int>)dm.CreateDelegate(typeof(Func<int>));
SizeOf = func();
}
}
}
答案 2 :(得分:15)
int
的大小始终为32位。为什么你需要在运行时获得大小?
话虽如此,您可以使用Marshal.SizeOf()
,但这仅适用于非托管代码。
我stumbled upon some code显然会给你一个值类型的大小。它使用反射,与你想要使用的功能(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<uint>)method.CreateDelegate(typeof(Func<uint>));
return checked((int)func());
}
答案 3 :(得分:4)
如果您正在构建数据包以发送到设备,请尝试以下操作:
byte[] dataBytes = BitConverter.GetBytes(x);
int dataLength= dataBytes.Length;
现在,您可以将dataBytes数组复制到dataPacket数组的Payload部分,dataLength将告诉您要复制多少字节,并让您验证或设置数据包中的PayloadLength值。
答案 4 :(得分:4)
public static class TypeSize
{
public static int GetSize<T>(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<Type, int> _cache = new ConcurrentDictionary<Type, int>();
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);
});
}
}
答案 5 :(得分:3)
我打算说使用类型推断来满足你的要求(“如果你改变x的类型从int改为long long,你不必用sizeof替换sizeof(int)的每一个出现(long long )“):
public unsafe void GetSizeOf<T>(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));
}
}
答案 6 :(得分:3)
向前推进并为CORY发布的代码添加了一些安全/性能/便利功能,因为较少偏执的LukeH代码应该足够了。
简而言之,这个类返回类型大小,确保尽可能使用缓存,并在外部类中包含异常。
您可能希望重写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<T>()
{
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>(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<int>)sizeOfMethod.CreateDelegate(typeof(Func<int>));
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<Type, int>();
}
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<Type, int> typeSizeCache;
}
答案 7 :(得分:0)
从 netcore1.0
开始,有 System.Runtime.CompilerServices.Unsafe.SizeOf
方法可以为您提供任何对象的大小。方法是在运行时实现的,所以应该很快。
注意:似乎该方法返回引用类型的指针大小(sizeof(IntPtr)
)而不是实际大小
用法:
Console.WriteLine(Unsafe.SizeOf<System.Guid>()); // 16