12

次のWin32API構造体について考えてみます。

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

このオブジェクトをC#に移植するときは、次のように、ここで使用されている名前の命名規則に従う必要があります。

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

または、次のように、すべてを実行して、構造体をC#スタイルで記述できますか?

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;
    }
}

2番目のアプローチははるかに洗練されているように見えますが、その方法で記述された構造体を使用してネイティブ機能を呼び出すことが賢明かどうか、またはC /C++から構造体を移植するときに他の落とし穴があるかどうかを知りたいと思います。

4

3 に答える 3

4

これはあなたの個人的な好みに帰着します。どのアプローチを選択するかについての主な考慮事項は、コードの保守の容易さです。個人的には、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...相互運用構造体とメソッドを使いやすいインターフェイスの背後に隠そうとしています。低レベルの相互運用機能の定義を強化する必要はないようです。

于 2012-12-19T19:12:16.320 に答える
3

これは個人的な好みではないと思います。コードを別の言語に移植する場合は、移植先の言語の規則を適用する必要があります。

コードはC/C ++開発者ではなくC#開発者によって使用されるので、私は確かにC#規則を使用しますよね?_int32 DWORDそれ以外の場合は、C#の醜いコードを使用します。

C#規則の優れたガイドは次のとおりです。

于 2012-12-19T19:28:52.903 に答える
0

完全を期すために、この回答を追加します。Mertとdgvidの回答から得られたポイントを組み合わせたものです。Win32RECT構造を使用した例を次に示します。

C / C ++の定義:

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

C#の定義:

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
    }
}

これはある程度完全な解決策を提供し、ネイティブコード呼び出しで使用する場合は適切にマップする必要があると思います。

余分な仕事:

この構造体では、現在、System.Drawing名前空間からSize、Pointを使用できます。Win32にもサイズとポイントの構造があるため、これらも使用できるようにするのが適切です。

于 2012-12-21T10:07:42.187 に答える