Jon Skeet と ValtasarIII の両方に同意しますが、データ型が(既知のレイアウトを持つ) 構造体であり、値型のみを含み、コードをunsafe
許可している場合、変数の生のバイトにアクセスすることは (恐ろしい方法で) 可能です。 .
以下は、マシンの境界を越えるために使用したい手法ではありません (また、実際に使用するべきではありません)。
TestStruct
そのように定義されたという構造が与えられた場合
[StructLayout(LayoutKind.Sequential)]
public struct TestStruct
{
public int A;
public int B;
}
そのコンテンツの生のバイトは、このように取得できます
private static unsafe byte[] GetBytes(TestStruct item)
{
//Figure out how big TestStruct is
var size = Marshal.SizeOf(item);
//Make an array large enough to hold all the bytes required
var array = new byte[size];
//Get a pointer to the struct
var itemPtr = &item;
//Change the type of the pointer from TestStruct* to byte*
var itemBytes = (byte*) itemPtr;
//Iterate from the first byte in the data to the last, copying the values into our
// temporary storage
for (var i = 0; i < size; ++i)
{
array[i] = itemBytes[i];
}
//Return the bytes that were found in the instance of TestStruct
return array;
}
そして、このような新しいものを構築できます
private static unsafe TestStruct Reconstitute(IList<byte> data)
{
//Figure out how big TestStruct is
var size = Marshal.SizeOf(typeof(TestStruct));
//If the data we've been presented with is either too large or too small to contain
// the data for exactly one TestStruct instance, throw an exception
if (data.Count != size)
{
throw new InvalidOperationException("Amount of data available is not the exact amount of data required to reconstitute the item");
}
//Make our temporary instance
var item = new TestStruct();
//Get a pointer to our temporary instance
var itemPtr = &item;
//Change the type of the pointer to byte*
var itemBytes = (byte*) itemPtr;
//Iterate from the first byte in the data to the last, copying the values into our
// temporary instance
for (var i = 0; i < size; ++i)
{
itemBytes[i] = data[i];
}
//Return our reconstituted structure
return item;
}
使用法:
static void Main()
{
var test = new TestStruct
{
A = 1,
B = 3
};
var bytes = GetBytes(test);
var duplicate = Reconstitute(bytes);
Console.WriteLine("Original");
PrintObject(test, 1);
Console.WriteLine();
Console.WriteLine("Reconstituted");
PrintObject(duplicate, 1);
Console.ReadLine();
}
そして、完全を期すために、コードPrintObject
static void PrintObject(object instance, int initialIndentLevel)
{
PrintObject(instance, initialIndentLevel, 4, ' ', new List<object>());
}
static void PrintObject(object instance, int level, int indentCount, char paddingChar, ICollection<object> printedObjects)
{
if (printedObjects.Contains(instance))
{
return;
}
var tabs = "".PadLeft(level * indentCount, paddingChar);
var instanceType = instance.GetType();
printedObjects.Add(instance);
foreach (var member in instanceType.GetMembers())
{
object value;
try
{
switch (member.MemberType)
{
case MemberTypes.Property:
var property = (PropertyInfo) member;
value = property.GetValue(instance, null);
break;
case MemberTypes.Field:
var field = (FieldInfo) member;
value = field.GetValue(instance);
break;
default:
continue;
}
}
catch
{
continue;
}
if (value == null || value.GetType().IsValueType || value.GetType().ToString() != value.ToString())
{
Console.WriteLine("{2}{0}: {1}", member.Name, (value ?? "(null)"), tabs);
}
else
{
var vals = value as IEnumerable;
if (vals != null)
{
var index = 0;
var indented = "".PadLeft((level + 1) * indentCount, paddingChar);
Console.WriteLine("{2}{0}: {1}", member.Name, value, tabs);
foreach (var val in vals)
{
Console.WriteLine("{1}[{0}]:", index++, indented);
PrintObject(val, level + 2, indentCount, paddingChar, printedObjects);
}
if (index == 0)
{
Console.WriteLine("{0}(No elements)", indented);
}
}
else
{
PrintObject(value, level + 1, indentCount, paddingChar, printedObjects);
}
}
}
}