6

私はバイト配列を持っています:

byte[] alldata = new byte[1024];

UInt32次に、このデータを次のように変換する必要があります。

UInt32[] block32 = new UInt32[(int)Math.Ceiling((double)alldata.Length / 4)];
Buffer.BlockCopy(alldata, 0, block32, 0, alldata.Length);

この後、配列にblock32戻す必要があります。byte

問題は、配列の変換と逆変換を回避するために、配列をblock32配列の32ビット参照配列にすることができるかどうかです。byteUInt32

4

3 に答える 3

12

あなたの質問は完全に明確ではありませんが、参照は単一のオブジェクトへの参照のみであり、配列オブジェクトはその実際の型を「認識」しています... auint[]を abyte[]またはその逆のように扱うことはできません。

できることは、それを別のオブジェクトの後ろに隠すことです。ByteArrayViewと の間で共有される単一のバイト配列を持つことができますUInt32ArrayView。これらのクラスはそれぞれ、単一の基になるバイト配列をアドレス指定する方法を知っています。ただし、これらのクラスは自分で作成する必要があります。既存のフレームワークのどこにも存在しないと思います。

たとえば、これらの異なるクラスが実装する抽象クラスまたはインターフェースを潜在的に作成することもできます。

class ByteArrayView : IArrayView<byte>
class UInt32ArrayView : IArrayView<uint>

IList<T>(もちろん、適切に実装するだけです...)

于 2013-01-07T11:42:01.947 に答える
1

Omer Morからここで見つけた回答を作り直しました。これは基本的に安全でないコードを使用して、配列が認識している型を一時的に変更します。

プラス面としては、安全でないポインターやラッパー クラスを使用するために他のコードを書き直す必要はありません。欠点としては、これは安全でないコードであるだけでなく、型システムをいじる厄介な安全でないコードです。

static class ArrayCaster
{
    [StructLayout(LayoutKind.Explicit)]
    private struct Union
    {
        [FieldOffset(0)]
        public Byte[] Bytes;
        [FieldOffset(0)]
        public UInt32[] UInt32s;
    }

    static unsafe int UInt32Id
    {
        get
        {
            fixed (UInt32* pUints = new UInt32[1])
            {
                var pBytes = (Byte*)pUints;
                return *(int*)(pBytes - 8);
            }
        }
    }

    static unsafe void SetSizeAndId(
        byte[] bytes,
        int newSize, int newId,
        out int oldSize, out int oldId)
    {
        fixed (Byte* pBytes = bytes)
        {
            int* size = (int*)(pBytes - 4);
            oldSize = *size;
            *size = newSize;
            int* id = (int*)(pBytes - 8);
            oldId = *id;
            *id = newId;
        }
    }

    public static void WithBytesAsUInt32s(
        Byte[] bytes, Action<UInt32[]> withUints)
    {
        if (bytes.Length % sizeof(UInt32) != 0) throw new ArgumentException();

        Union u = new Union { Bytes = bytes };
        int origSize, origId;
        SetSizeAndId(bytes, bytes.Length / sizeof(UInt32), UInt32Id,
                     out origSize, out origId);
        try
        {
            withUints(u.UInt32s);
        }
        finally
        {
            SetSizeAndId(bytes, origSize, origId, out origSize, out origId);
        }
    }
}

あなたのコードで:

byte allData = new byte[1024];
ArrayCaster.WithBytesAsUInt32s(allData, uintArray => Encrypt(unitArray));

編集:暗号化/復号化メソッドが配列と同様に明示的な長さを取る可能性がある場合は、コードを完全UInt32に切り取ることができます。(a) デバッガーのインスペクターが混乱し、(b) 長さが更新されないことを除いて、正常に動作します。配列の 4 分の 1 のみを使用するようにメソッドに指示できれば、成功です。unsafeUnion

于 2013-01-07T12:23:22.907 に答える
0

As you already mentioned you will use the uint[] for encryption.

Because of some reasons, you copy arrays with BlockCopy. But you want to access byte[] like an uint[], without converting or casting the entire array.

Then, what's something not enough? Is there something in C# can do this?

After think for one more hour, I guess what you want it for, should be the indexer.

Here's the code. It's simple.

public partial class UIntIndexer {
    static int ComputeElementCount(int size, int bytesCount) {
        var r=~0;
        return Math.DivRem(bytesCount, size, out r)+(r>0?1:0);
    }

    static int ComputeIndex(int index) {
        return sizeof(uint)*index;
    }

    public UIntIndexer(byte[] array) {
        m_Length=ComputeElementCount(sizeof(uint), (m_Array=array).Length);
    }

    public uint this[int index] {
        set {
            var startIndex=ComputeIndex(index);
            var bytes=BitConverter.GetBytes(value);
            var count=m_Length>1+index?sizeof(uint):m_Array.Length-startIndex;
            Buffer.BlockCopy(bytes, 0, m_Array, startIndex, count);
        }

        get {
            var startIndex=ComputeIndex(index);

            if(m_Length>1+index)
                return BitConverter.ToUInt32(m_Array, startIndex);
            else {
                var bytes=new byte[sizeof(uint)];
                Buffer.BlockCopy(m_Array, startIndex, bytes, 0, m_Array.Length-startIndex);
                return BitConverter.ToUInt32(bytes, 0);
            }
        }
    }

    public int Length {
        get {
            return m_Length;
        }
    }

    byte[] m_Array;
    int m_Length;
}

If thread safety should be concerned, you might need to keep the the source array synchronized. Following is the code for test it:

var alldata=new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var block32=new byte[alldata.Length];
var uintIndexer=new UIntIndexer(block32);
Buffer.BlockCopy(alldata, 0, block32, 0, alldata.Length);

Debug.Print("uintIndexer.Length={0}", uintIndexer.Length);

for(var i=uintIndexer.Length; i-->0; )
    Debug.Print("uintIndexer[{0}]={1}", i, uintIndexer[i]);
于 2013-01-07T15:11:48.363 に答える