Существует ли альтернатива для атрибута “Пакета” StructLayout в Компактной Платформе?

Был язык программирования Pizza (расширение Java), и вы должны взглянуть на него. - Он использует концепцию «плавных интерфейсов» для запроса данных декларативным способом, что в принципе идентично LINQ без выражений запросов (http://en.wikipedia.org/wiki/Pizza_programming_language). Но, увы, это не преследовалось, но это был бы один из способов получить что-то похожее на LINQ в Java.

6
задан PeeHaa 3 November 2013 в 17:45
поделиться

7 ответов

Вероятно, это не тот тип ответа, который вы ищете, но я все равно отправлю его, черт возьми:

public struct SomeStruct
{
    public byte SomeByte;
    public int SomeInt;
    public short SomeShort;
    public byte SomeByte2;


    public byte[] APIStruct
    {
        get
        {
            byte[] output = new byte[8];
            output[0] = this.SomeByte;
            Array.Copy(BitConverter.GetBytes(this.SomeInt), 0,
                output, 1, 4);
            Array.Copy(BitConverter.GetBytes(this.SomeShort), 0,
                output, 5, 2);
            output[7] = this.SomeByte2;
            return output;
        }
        set
        {
            byte[] input = value;
            this.SomeByte = input[0];
            this.SomeInt = BitConverter.ToInt32(input, 1);
            this.SomeShort = BitConverter.ToInt16(input, 5);
            this.SomeByte2 = input[7];
        }
    }
}

В основном он сам упаковывает / распаковывает собственность APIStruct.

6
ответ дан 8 December 2019 в 17:26
поделиться

You need to post a more relevant example. Setting packing on that struct would have no effect anyway.

My bet is that you need to use LaoutKind.Explicit and then give the offsets for each member. It's way better than messing with the packing anyway, because it's way more obvious to someone looking at the code that the original developer explicitly meant for things to be unaligned.

Something along these lines:

[StructLayout(LayoutKind.Explicit)]
struct Foo
{
    [FieldOffset(0)]
    byte a;
    [FieldOffset(1)]
    uint b;
}
1
ответ дан 8 December 2019 в 17:26
поделиться

LayoutKind.Explicit лучше всего подходит для определения конкретной схемы памяти. Однако не используют LayoutKind.Explicit для структур, которые содержат значения размера указателя , такие как истинные указатели, дескрипторы операционной системы или IntPtr s; это просто вызывает загадочные проблемы во время выполнения на случайных платформах.

В частности, LayoutKind.Explicit является плохой заменой анонимным объединениям . Если ваша целевая структура содержит анонимное объединение, преобразуйте его в именованное объединение; вы можете безопасно представить именованное объединение в виде структуры с помощью LayoutKind.Explicit , где все смещения равны 0 .

0
ответ дан 8 December 2019 в 17:26
поделиться

Простейший метод решения проблемы этого типа - такой же, как и для битового поля, просто упакуйте свои данные в закрытый член (или члены, если он большой) соответствующий тип данных, а затем представляют общедоступные свойства, которые распаковывают данные за вас. Операции распаковки происходят очень быстро и практически не влияют на производительность. Для вашего конкретного типа, вероятно, вам нужно следующее:

public struct SomeStruct
{
    private long data;

    public byte SomeByte { get { return (byte)(data & 0x0FF); } }
    public int SomeInt { get { return (int)((data & 0xFFFFFFFF00) << 8); } }
    public short SomeShort { get { return (short)((data & 0xFFFF0000000000) << 40); } }
    public byte SomeByte2 { get { return (byte)((data & unchecked((long)0xFF00000000000000)) << 56); } }
}

Для некоторых структур даже этот метод не работает из-за неудачного способа определения структуры. В этих случаях вам, как правило, придется использовать массив байтов в качестве большого двоичного объекта данных, из которого можно распаковать элементы.

РЕДАКТИРОВАТЬ: Чтобы расширить то, что я имею в виду о структурах, которые нельзя обработать с помощью этого простого метода. Когда ты можешь' Чтобы выполнить простую упаковку / распаковку, как это, вам нужно вручную упорядочить нерегулярную структуру. Это можно сделать с помощью ручных методов в момент вызова API pInvoked или с помощью настраиваемого маршалера. Ниже приведен пример специализированного маршалинга, который можно легко адаптировать к маршалингу вручную на месте.

using System.Runtime.InteropServices;
using System.Threading;

public class Sample
{
    [DllImport("sample.dll")]
    public static extern void TestDataMethod([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(TestDataMarshaler))] TestDataStruct pData);
}

public class TestDataStruct
{
    public byte data1;
    public int data2;
    public byte[] data3 = new byte[7];
    public long data4;
    public byte data5;
}

public class TestDataMarshaler : ICustomMarshaler
{
    //thread static since this could be called on 
    //multiple threads at the same time.
    [ThreadStatic()]
    private static TestDataStruct m_MarshaledInstance;

    private static ICustomMarshaler m_Instance = new TestDataMarshaler();

    public static ICustomFormatter GetInstance(string cookie)
    {
        return m_Instance;
    }

    #region ICustomMarshaler Members

    public void CleanUpManagedData(object ManagedObj)
    {
        //nothing to do.
    }

    public void CleanUpNativeData(IntPtr pNativeData)
    {
        Marshal.FreeHGlobal(pNativeData);
    }

    public int GetNativeDataSize()
    {
        return 21;
    }

    public IntPtr MarshalManagedToNative(object ManagedObj)
    {
        m_MarshaledInstance = (TestDataStruct)ManagedObj;
        IntPtr nativeData = Marshal.AllocHGlobal(GetNativeDataSize());

        if (m_MarshaledInstance != null)
        {
            unsafe //unsafe is simpler but can easily be done without unsafe if necessary
            {
                byte* pData = (byte*)nativeData;
                *pData = m_MarshaledInstance.data1;
                *(int*)(pData + 1) = m_MarshaledInstance.data2;
                Marshal.Copy(m_MarshaledInstance.data3, 0, (IntPtr)(pData + 5), 7);
                *(long*)(pData + 12) = m_MarshaledInstance.data4;
                *(pData + 20) = m_MarshaledInstance.data5;
            }
        }
        return nativeData;
    }

    public object MarshalNativeToManaged(IntPtr pNativeData)
    {
        TestDataStruct data = m_MarshaledInstance;
        m_MarshaledInstance = null; //clear out TLS for next call.

        if (data == null) data = new TestDataStruct(); //if no in object then return a new one

        unsafe //unsafe is simpler but can easily be done without unsafe if necessary
        {
            byte* pData = (byte*)pNativeData;
            data.data1 = *pData;
            data.data2 = *(int*)(pData + 1);
            Marshal.Copy((IntPtr)(pData + 5), data.data3, 0, 7);
            data.data4 = *(long*)(pData + 12);
            data.data5 = *(pData + 20);
        }
        return data;
    }

    #endregion
}

В случае массивов этих структур вы не можете использовать настраиваемый маршалинг, если размер массива не фиксирован, но относительно легко вручную маршалировать данные массива в целом, используя те же методы.

4
ответ дан 8 December 2019 в 17:26
поделиться

Метод count доступен только в Ruby 1.9 и выше. Я рекомендую вам использовать ту же версию Ruby, что и ваш сервер, чтобы избежать подобных проблем - в 1.9 многое изменилось.

[StructLayout(LayoutKind.Explicit, Size=8)]
public struct SomeStruct
{ 
   [FieldOffset(0)] private byte b0;
   [FieldOffset(1)] private byte b1;
   [FieldOffset(2)] private byte b2;
   [FieldOffset(3)] private byte b3;
   [FieldOffset(4)] private byte b4;
   [FieldOffset(5)] private byte b5;
   [FieldOffset(6)] private byte b6;
   [FieldOffset(7)] private byte b7;

   // not thread safe - alter accordingly if that is a requirement
   private readonly static byte[] scratch = new byte[4];       

   public byte SomeByte 
   { 
       get { return b0; }
       set { b0 = value; }
   }

   public int SomeInt
   {
       get 
       { 
           // get the right endianess for your system this is just an example!
           scratch[0] = b1;
           scratch[1] = b2;
           scratch[2] = b3;
           scratch[3] = b4;
           return BitConverter.ToInt32(scratch, 0);
       }
   }

   public short SomeShort
   {
        get 
        { 
            // get the right endianess for your system this is just an example!
            scratch[0] = b5;
            scratch[1] = b6;
            return BitConverter.ToInt16(scratch, 0);
        }
    }

    public byte SomeByte2 
    { 
        get { return b7; }
        set { b7 = value; }
    }
}
2
ответ дан 8 December 2019 в 17:26
поделиться

LayoutKind.Explicit и FieldOffsetAttribute позволят вам делать все, что вы можете делать со свойством Pack. Эти явные атрибуты макета позволяют указать точное положение байта каждого поля в структуре (относительно начала диапазона памяти структуры). Свойство Pack используется средой выполнения, чтобы помочь определить точное положение каждого поля при использовании последовательного макета. Свойство pack не имеет никакого другого эффекта, поэтому использование явного макета позволяет имитировать точно такое же поведение, хотя и немного более подробно. Если вы не думаете, что это решает вашу проблему, возможно, вы могли бы опубликовать немного больше информации о том, что вы пытаетесь сделать или почему вы думаете, что вам нужно использовать свойство Pack.

Изменить: я только что заметил дополнительный комментарий о попытке получить всю структуру ' s размером до 8 байт. Вы пробовали использовать свойство StructLayoutAttribute.Size? В отличие от Pack, он доступен в Compact Framework.

0
ответ дан 8 December 2019 в 17:26
поделиться

Я думаю, что нужно принять ответ Стивена Мартина, заставить его принимать т и использовать отражение для общей реализации маршалманагенционных и маршалнативетровых методов. Затем у вас будет пользовательский упакованный структурный маршалер, который будет работать на любой тип структуры.

Вот код:

using System;
using System.Threading;
using System.Reflection;
using System.Runtime.InteropServices;

namespace System.Runtime.InteropServices
{
    public class PinnedObject : IDisposable
    {
        private GCHandle gcHandle = new GCHandle();
        public PinnedObject(object o)
        {
            gcHandle = GCHandle.Alloc(o, GCHandleType.Pinned);
        }

        public unsafe static implicit operator byte*(PinnedObject po)
        {
            return (byte*)po.gcHandle.AddrOfPinnedObject();
        }

        #region IDisposable Members
        public void Dispose()
        {
            if (gcHandle.IsAllocated)
            {
                gcHandle.Free();
            }
        }
        #endregion
    }

    public class PackedStructMarshaler<T> : ICustomMarshaler where T : struct
    {
        private static ICustomMarshaler m_instance = new PackedStructMarshaler<T>();

        public static ICustomMarshaler GetInstance()
        {
            return m_instance;
        }

        private void ForEachField(Action<FieldInfo> action)
        {
            foreach (var fi in typeof(T).GetFields(BindingFlags.Public | BindingFlags.NonPublic))
            {
                // System.Diagnostics.Debug.Assert(fi.IsValueType);
                action(fi);
            }
        }

        private unsafe void MemCpy(byte* dst, byte* src, int numBytes)
        {
            for (int i = 0; i < numBytes; i++)
            {
                dst[i] = src[i];
            }
        }

        #region ICustomMarshaler Members
        public void CleanUpManagedData(object ManagedObj)
        {
        }

        public void CleanUpNativeData(IntPtr pNativeData)
        {
            Marshal.FreeHGlobal(pNativeData);
        }

        public int GetNativeDataSize()
        {
            unsafe
            {
                int ret = 0;
                ForEachField(
                    (FieldInfo fi) =>
                    {
                        Type ft = fi.FieldType;
                        ret += Marshal.SizeOf(ft);
                    });
                return ret;
            }
        }

        private object m_marshaledObj = null;

        public unsafe IntPtr MarshalManagedToNative(object obj)
        {
            IntPtr nativeData = (IntPtr)0;

            if (obj != null)
            {
                if (m_marshaledObj != null)
                    throw new ApplicationException("This instance has already marshaled a managed type");

                m_marshaledObj = obj;

                nativeData = Marshal.AllocHGlobal(GetNativeDataSize());
                byte* pData = (byte*)nativeData;
                int offset = 0;

                ForEachField(
                    (FieldInfo fi) =>
                    {
                        int size = Marshal.SizeOf(fi.FieldType);
                        using (PinnedObject po = new PinnedObject(fi.GetValue(obj)))
                        {
                            MemCpy(pData + offset, po, size);
                        }
                        offset += size;
                    });
            }

            return nativeData;
        }

        public object MarshalNativeToManaged(IntPtr pNativeData)
        {
            if (m_marshaledObj != null)
                m_marshaledObj = null;

            unsafe
            {
                byte* pData = (byte*)pNativeData;
                int offset = 0;

                object res = new T();

                ForEachField(
                    (FieldInfo fi) =>
                    {
                        int size = Marshal.SizeOf(fi.FieldType);
                        fi.SetValue(res, (object)(*((byte*)(pData + offset))));
                        offset += size;
                    });

                return res;
            }
        }

        #endregion
    }
}
1
ответ дан 8 December 2019 в 17:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: