System.Runtime.InteropServices
System.Runtime.CompilerServices
unsafe void Main()
{
Console.WriteLine(SizeOf(typeof(Sample)));
Console.WriteLine(SizeOf(typeof(Int32)));
Console.WriteLine(SizeOf(typeof(Int64)));
Console.WriteLine(SizeOf(typeof(Int16)));
Console.WriteLine(SizeOf(typeof(Char)));
Console.WriteLine(SizeOf(typeof(double)));
Console.WriteLine(SizeOf(typeof(IEnumerable)));
Console.WriteLine(SizeOf(typeof(List)));
Console.WriteLine(SizeOf(typeof(GenericSample)));
Console.WriteLine(SizeOf(typeof(GenericSample)));
Console.WriteLine(SizeOf(typeof(GenericSample)));
Console.WriteLine(SizeOf(typeof(GenericSample)));
Console.WriteLine(SizeOf(typeof(string)));
Console.WriteLine(SizeOf(new int[] {1}.GetType()));
Console.WriteLine(SizeOf(new int[] {1,2,3}.GetType()));
Action stringWriter = (arg) =>
{
Console.WriteLine($"Length of `{arg}` string: {SizeOf(arg)}");
};
stringWriter("a");
stringWriter("ab");
stringWriter("abc");
stringWriter("abcd");
stringWriter("abcde");
stringWriter("abcdef");
Console.WriteLine($"size of int[]{{1,2}}: {SizeOf(new int[2])}");
Console.WriteLine($"size of int[2,1]{{1,2}}: {SizeOf(new int[1,2])}");
Console.WriteLine($"size of int[2,3,4,5]{{...}}: {SizeOf(new int[2, 3, 4, 5])}");
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
unsafe int SizeOf(Type type)
{
var pvmt = (MethodTable*)type.TypeHandle.Value.ToPointer();
return pvmt->Size;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
int SizeOf()
{
return SizeOf(typeof(T));
}
unsafe int SizeOf(object obj)
{
var majorNetVersion = Environment.Version.Major;
var type = obj.GetType();
var href = Union.GetRef(obj).ToInt64();
var DWORD = sizeof(IntPtr);
var baseSize = 3 * DWORD;
if (type == typeof(string))
{
if (majorNetVersion >= 4)
{
var length = (int)*(int*)(href + DWORD /* skip vmt */);
return DWORD * ((baseSize + 2 + 2 * length + (DWORD-1)) / DWORD);
}
else
{
// on 1.0 -> 3.5 string have additional RealLength field
var arrlength = *(int*)(href + DWORD /* skip vmt */);
var length = *(int*)(href + DWORD /* skip vmt */ + 4 /* skip length */);
return DWORD * ((baseSize + 2 + 2 * length + (DWORD -1)) / DWORD);
}
}
else
if (type.BaseType == typeof(Array) || type == typeof(Array))
{
return ((ArrayInfo*)href)->SizeOf();
}
return SizeOf(type);
}
[StructLayout(LayoutKind.Explicit)]
public struct MethodTable
{
[FieldOffset(0)]
public MethodTableFlags Flags;
[FieldOffset(4)]
public short Size;
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct ArrayInfo
{
private MethodTable* MethodTable;
private IntPtr TotalLength;
private int Lengthes;
public bool IsMultidimentional
{
get
{
return (MethodTable->Flags & MethodTableFlags.IfArrayThenMultidim) == 0;
}
}
public bool IsValueTypes
{
get
{
return (MethodTable->Flags & MethodTableFlags.IfArrayThenSharedByReferenceTypes) == 0;
}
}
public int Dimensions
{
get
{
if (IsMultidimentional)
{
fixed (IntPtr* cur = &TotalLength)
{
var count = 0;
while (((int*)cur)[count] != 0) count++;
return count;
}
}
return 1;
}
}
public int GetLength(int dim)
{
var maxDim = Dimensions;
if (maxDim < dim)
throw new ArgumentOutOfRangeException("dim");
fixed (int* addr = &Lengthes)
{
return addr[dim];
}
}
public int SizeOf()
{
var total = 0;
int elementsize;
fixed (void* entity = &MethodTable)
{
var arr = Union.GetObj((IntPtr)entity);
var elementType = arr.GetType().GetElementType();
if (elementType.IsValueType)
{
var typecode = Type.GetTypeCode(elementType);
switch (typecode)
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.Boolean:
elementsize = 1;
break;
case TypeCode.Int16:
case TypeCode.UInt16:
case TypeCode.Char:
elementsize = 2;
break;
case TypeCode.Int32:
case TypeCode.UInt32:
case TypeCode.Single:
elementsize = 4;
break;
case TypeCode.Int64:
case TypeCode.UInt64:
case TypeCode.Double:
elementsize = 8;
break;
case TypeCode.Decimal:
elementsize = 12;
break;
default:
var info = (MethodTable*)elementType.TypeHandle.Value;
elementsize = info->Size - 2 * sizeof(IntPtr); // sync blk + vmt ptr
break;
}
}
else
{
elementsize = IntPtr.Size;
}
// Header
total += 3 * sizeof(IntPtr); // sync blk + vmt ptr + total length
total += elementType.IsValueType ? 0 : sizeof(IntPtr); // MethodsTable for refTypes
total += IsMultidimentional ? Dimensions * sizeof(int) : 0;
}
// Contents
total += (int)TotalLength * elementsize;
// align size to IntPtr
if ((total % sizeof(IntPtr)) != 0)
{
total += sizeof(IntPtr) - total % (sizeof(IntPtr));
}
return total;
}
}
class Sample
{
int x;
}
class GenericSample
{
T fld;
}
[StructLayout(LayoutKind.Explicit)]
public class Union
{
public Union()
{
IntPtr = new Holder();
Reference = new Holder