0

たとえば、C#のオーキーでオブジェクトのバイトにアクセスしたい:

WCF でクラスをシリアル化すると、シリアライザーはクラス オブジェクトのすべてのバイトを読み取り、最後に SOAP メッセージを読み取ります。

オブジェクトのバイトを読み取り、そのバイトでオブジェクトを再作成する方法を知っている

//x_obj created and we allocate an address & size of RAM (memory) to it Now its byts structure is in the RAM

X_calss x_obj = new X_class(); 

//and now we want to read the x_obj bytes in RAM
unsafe byte[] READ(X_class x_obj){
 xobj_pointer = &x_obj;//pointer to address of obj in RAM
 byte[] xobj_bytes = read_from(xobj_pointer,sizeof(x_obj));//Some Way To Read Byte of x_obj
 return xobj_bytes;
}
// and now we want to recreate class by it bytes stream
unsafe X_class Creative(byte[] xobj_bytes){
 x_pointer = Memory_allocate(sizeof(X_class));//reserve an address of RAM
 write_to(x_pointer,xobj_bytes);//write bytes to RAM 
 X_class x_obj = (X_class)*(x_pointer);//recreate the class by content of pointer
 return x_obj;
}
4

3 に答える 3

5

たとえば、C#でオブジェクトのバイトにアクセスしたい

あなたは絶対にそうしません。始める理由は 2 つあります。

  • オブジェクトのレイアウトは、サーバーとクライアントで異なる可能性があります。特に、一方が 64 ビット CLR を使用し、もう一方が 32 ビット CLR を使用している場合
  • オブジェクトには、賢明に伝播できない同期ブロックなどのプロセス固有のデータが含まれています
  • 「ソース」マシンでの参照は、おそらく「ターゲット」マシンでは有効ではありません

この単純なクラスに含まれるバイトを考えてみましょう:

class Foo
{
    string name;
}

ここでのデータの「バイト」は参照だけで構成されています。この質問の目的のために、参照が実際には単純なポインターであると想像してみましょう。メモリ アドレス 0x12345678 へのポインタが、そのアドレスを別のプロセスにコピーした場合、同じ内容の文字列を参照する可能性はほとんどありません。

この種のことこそが、シリアライザーがある理由です。メモリ自体のコピーを取得するだけでは十分ではありません。

于 2012-11-28T09:28:20.513 に答える
2

C# は、メモリ操作に関して C と同等ではありません。

1.Serializable 属性を持つオブジェクトのクラスをマークします。

2. バイトにシリアル化:


public byte[] ObjectToByteArray(Object obj)
{
    BinaryFormatter bf = new BinaryFormatter();
    MemoryStream ms = new MemoryStream();
    bf.Serialize(ms, obj);
    return ms.ToArray();
}

3. オブジェクトへの逆シリアル化:


public object BytesToObject(byte[] bytes)
{
        MemoryStream ms = new MemoryStream(bytes);
        BinaryFormatter bf= new BinaryFormatter();
        ms.Position = 0;
        return bf.Deserialize(ms);
}

于 2012-11-28T09:39:56.953 に答える
1

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);
            }
        }
    }
}
于 2012-11-28T10:33:16.347 に答える