Подтвердить что ты не робот

Соглашения о совместимости с C/С++ с С#

Рассмотрим следующую структуру API Win32:

typedef struct _SECURITY_ATTRIBUTES {
  DWORD  nLength;
  LPVOID lpSecurityDescriptor;
  BOOL   bInheritHandle;
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;

При переносе этого объекта на С#, следует ли следовать правилам именования имен, которые используются здесь:

public struct _SECURITY_ATTRIBUTES
{
    public int nLength;
    public unsafe byte* lpSecurityDescriptor;
    public int bInheritHandle;
}

или я могу изо всех сил и написать свою структуру в стиле С#, например:

public struct SecurityAttributes
{
    private int length;
    private unsafe byte* securityDescriptor;
    private int bInheritHandle;

    public Int32 Length
    {
        get { return this.length; }
        set { this.length = value; }
    }

    public Byte* SecurityDescriptor
    {
        get { return this.seurityDescriptor; }
        set { this.securityDescriptor = value; }
    }

    public Int32 InheritHandle
    {
        get { return this.bInheritHandle; }
        set { this.bInheritHandle = value; }
    }

    public SecurityAttributes(int length, byte* securityDescriptor, int inheritHandle)
    {
        this.length = length;
        this.securityDescriptor = securityDescriptor;
        this.inheritHandle = inheritHandle;
    }
}

В то время как второй подход выглядит намного более элегантным, я хотел бы знать, целесообразно ли вызывать встроенные функции с использованием структуры, написанной таким образом, или если есть какие-либо другие ошибки при переносе структур из C/С++.

4b9b3361

Ответ 1

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

Я бы, конечно, использовал соглашения С#, так как код будет использоваться разработчиками С#, а не разработчиками C/С++, правильно? В противном случае мы все равно будем использовать уродливый _int32 DWORD код в С#.

Вот несколько хороших руководств для конвенций С#:

Ответ 2

Это сводится к вашим личным предпочтениям. Ваше основное соображение, в котором подход к выбору должен быть простота обслуживания кода. Лично я предпочитаю придерживаться тех же имен, что и те, которые используются в декларации C, потому что это облегчает понимание того, что я ищу. Например, если я определяю структуру следующим образом:

/// <summary>
/// Unmanaged sockaddr_in structure from Ws2def.h.
/// </summary>
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct sockaddr_in
{
    /// <summary>
    /// short sa_family;
    /// </summary>
    public short sa_family;

    /// <summary>
    /// unsigned short sin_port;
    /// </summary>
    public ushort sin_port;

    /// <summary>
    /// struct in_addr addr;
    /// </summary>
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 4)]
    public byte[] addr;

    /// <summary>
    /// char sin_zero[8];
    /// </summary>
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 8)]
    public byte[] sin_zero;
}

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

Конечно, я мог бы добавить красиво названные геттеры и сеттеры в структуре, например, public short Family... Однако я пытаюсь скрыть структуры и методы взаимодействия из более простого в использовании интерфейса. Выражение определений интерполя низкого уровня просто не представляется необходимым.

Ответ 3

Я добавляю этот ответ ради полноты. Он объединяет точки из ответов Mert и dgvid. Вот пример использования структуры REST Win32.

Определение C/С++:

typedef struct _RECT {
  LONG left;
  LONG top;
  LONG right;
  LONG bottom;
} RECT, *PRECT;

Определение С#:

namespace NetBlast.Runtime.PlatformInvoke.Windows
{
    #region USING

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;
    using System.Text;

    #endregion

    /// <summary>
    /// The Rect (RECT) structure defines the coordinates of the upper-left and lower-right corners of a rectangle.
    /// </summary>
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public struct Rect : IEquatable<Rect>, IEquatable<Rectangle>, ICloneable
    {
        #region CONSTANTS



        #endregion

        #region VARIABLES

        /// <summary>
        /// Win32 RECT.left value.
        /// </summary>
        private int left;

        /// <summary>
        /// Win32 RECT.top value.
        /// </summary>
        private int top;

        /// <summary>
        /// Win32 RECT.right value.
        /// </summary>
        private int right;

        /// <summary>
        /// Win32 RECT.bottom value.
        /// </summary>
        private int bottom;

        #endregion

        #region PROPERTIES

        /// <summary>
        /// Gets or sets the x-coordinate of the upper-left corner of the rectangle.
        /// </summary>
        public Int32 Left
        {
            get { return this.left; }
            set { this.left = value; }
        }

        /// <summary>
        /// Gets or sets the y-coordinate of the upper-left corner of the rectangle.
        /// </summary>
        public Int32 Top
        {
            get { return this.top; }
            set { this.top = value; }
        }

        /// <summary>
        /// Gets or sets the x-coordinate of the lower-right corner of the rectangle.
        /// </summary>
        public Int32 Right
        {
            get { return this.right; }
            set { this.right = value; }
        }

        /// <summary>
        /// Gets or sets the y-coordinate of the lower-right corner of the rectangle.
        /// </summary>
        public Int32 Bottom
        {
            get { return this.bottom; }
            set { this.bottom = value; }
        }

        /// <summary>
        /// Gets or sets the height of the rectangle.
        /// </summary>
        public Int32 Height
        {
            get { return this.bottom - this.top; }
            set { this.bottom = value + this.top; }
        }

        /// <summary>
        /// Gets or sets the width of the rectangle.
        /// </summary>
        public Int32 Width
        {
            get { return this.right - this.left; }
            set { this.right = value + this.left; }
        }

        /// <summary>
        /// Gets or sets the top, left location of the rectangle.
        /// </summary>
        public Point Location
        {
            get
            {
                return new Point(this.left, this.top);
            }

            set
            {
                this.right = this.left - value.X;
                this.bottom = this.top - value.Y;
                this.left = value.X;
                this.top = value.Y;
            }
        }

        /// <summary>
        /// Gets or sets the size of the rectangle.
        /// </summary>
        public Size Size
        {
            get
            {
                return new Size(this.Width, this.Height);
            }

            set
            {
                this.right = value.Width + this.left;
                this.bottom = value.Height + this.top;
            }
        }

        #endregion

        #region CONSTRUCTORS / FINALIZERS

        /// <summary>
        /// Initializes a new instance of the <see cref="Rect" /> struct.
        /// </summary>
        /// <param name="location">The top, left location of the rectangle.</param>
        /// <param name="size">The size of the rectangle.</param>
        public Rect(Point location, Size size)
        {
            this.left = default(int);
            this.top = default(int);
            this.right = default(int);
            this.bottom = default(int);
            this.Location = location;
            this.Size = size;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Rect" /> struct.
        /// </summary>
        /// <param name="left">The x-coordinate of the upper-left corner of the rectangle.</param>
        /// <param name="top">The y-coordinate of the upper-left corner of the rectangle.</param>
        /// <param name="right">The x-coordinate of the lower-right corner of the rectangle.</param>
        /// <param name="bottom">The y-coordinate of the lower-right corner of the rectangle.</param>
        public Rect(int left, int top, int right, int bottom)
        {
            this.left = left;
            this.top = top;
            this.right = right;
            this.bottom = bottom;
        }

        #endregion

        #region OPERATORS

        /// <summary>
        /// Provides implicit casting from Rect to Rectangle.
        /// </summary>
        /// <param name="rectangle">The Rect instance to cast.</param>
        /// <returns>A Rectangle representation of the Rect instance.</returns>
        public static implicit operator Rectangle(Rect rectangle)
        {
            return new Rectangle(rectangle.Location, rectangle.Size);
        }

        /// <summary>
        /// Provides implicit casting from Rectangle to Rect.
        /// </summary>
        /// <param name="rectangle">The Rectangle instance to cast.</param>
        /// <returns>A Rect representation of the Rectangle instance.</returns>
        public static implicit operator Rect(Rectangle rectangle)
        {
            return new Rect(rectangle.Location, rectangle.Size);
        }

        /// <summary>
        /// Performs an equality check between two instances of Rect.
        /// </summary>
        /// <param name="a">Instance a of Rect.</param>
        /// <param name="b">Instance b of Rect.</param>
        /// <returns>True if the instances are equal, otherwise false.</returns>
        public static bool operator ==(Rect a, Rect b)
        {
            return a.Equals(b);
        }

        /// <summary>
        /// Performs an inequality check between two instances of Rect.
        /// </summary>
        /// <param name="a">Instance a of Rect.</param>
        /// <param name="b">Instance b of Rect.</param>
        /// <returns>True if the instances are not equal, otherwise false.</returns>
        public static bool operator !=(Rect a, Rect b)
        {
            return !a.Equals(b);
        }

        #endregion

        #region STATIC METHODS



        #endregion

        #region INSTANCE METHODS

        /// <summary>
        /// Indicates whether the current object is equal to another object of the same type.
        /// </summary>
        /// <param name="obj">An object to compare with this object.</param>
        /// <returns>True if the instances are not equal, otherwise false.</returns>
        public override bool Equals(object obj)
        {
            return this.Equals((Rect)obj);
        }

        /// <summary>
        /// Serves as a hash function for this instance of Rect.
        /// </summary>
        /// <returns>A hash code for the current Rect.</returns>
        public override int GetHashCode()
        {
            return ObjectUtilities.CreateHashCode(this.left, this.top, this.right, this.bottom);
        }

        /// <summary>
        /// Returns a string representation of this instance.
        /// </summary>
        /// <returns>A string representation of this instance.</returns>
        public override string ToString()
        {
            return string.Format("Left: {0}; Top: {1}; Right: {2}; Bottom: {3};", this.left, this.top, this.right, this.bottom);
        }

        /// <summary>
        /// Indicates whether the current object is equal to another object of the same type.
        /// </summary>
        /// <param name="other">A Rect instance to compare with this object.</param>
        /// <returns>True if the instances are not equal, otherwise false.</returns>
        public bool Equals(Rect other)
        {
            return this.left == other.left
                && this.top == other.top
                && this.right == other.right
                && this.bottom == other.bottom;
        }

        /// <summary>
        /// Indicates whether the current object is equal to another object of the same type.
        /// </summary>
        /// <param name="other">A Rectangle instance to compare with this object.</param>
        /// <returns>True if the instances are not equal, otherwise false.</returns>
        public bool Equals(Rectangle other)
        {
            return this.left == other.Left
                && this.top == other.Top
                && this.right == other.Right
                && this.bottom == other.Bottom;
        }

        /// <summary>
        /// Returns a clone of this Rect instance.
        /// </summary>
        /// <returns>A clone of this Rect instance.</returns>
        public object Clone()
        {
            return new Rect(this.left, this.top, this.right, this.bottom);
        }

        #endregion

        #region DELEGATES & EVENTS



        #endregion

        #region CLASSES & STRUCTURES



        #endregion
    }
}

Я чувствую, что это обеспечит несколько полное решение и будет соответствующим образом отображаться при использовании с собственными вызовами кода.

Дополнительная работа:

В настоящее время эта структура позволяет использовать Size, Point из пространства имен System.Drawing. Поскольку Win32 также имеет структуры размера и точки, будет также целесообразно также использовать их.