C# C/C++;与C语言的互操作性命名约定#
考虑以下Win32 API结构:C# C/C++;与C语言的互操作性命名约定#,c#,c++,c,winapi,pinvoke,C#,C++,C,Winapi,Pinvoke,考虑以下Win32 API结构: typedef struct _SECURITY_ATTRIBUTES { DWORD nLength; LPVOID lpSecurityDescriptor; BOOL bInheritHandle; } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES; 将此对象移植到C#时,是否应遵循此处使用的名称命名约定,如: public struct _SECU
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;
}
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#风格写我的结构,就像这样:
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/C++移植结构时是否存在任何其他缺陷。这取决于您的个人偏好。选择哪种方法的主要考虑因素应该是代码维护的方便性。就个人而言,我倾向于使用与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;
}
//
///Ws2def.h中结构中的非托管sockaddr_。
///
[StructLayoutAttribute(LayoutKind.Sequential,CharSet=CharSet.Ansi)]
中的公共结构sockaddr\u
{
///
///短萨乌家族;
///
公共短萨乌家庭;
///
///无符号短sinu端口;
///
公共乌斯波特新港;
///
///地址中的结构;
///
[Marshallas(UnmanagedType.ByValArray,ArraySubType=UnmanagedType.I1,SizeConst=4)]
公共字节[]地址;
///
///char sin_zero[8];
///
[Marshallas(UnmanagedType.ByValArray,ArraySubType=UnmanagedType.I1,SizeConst=8)]
公共字节[]sin_零;
}
后来我或同事想知道sa_家族到底是什么,我们可以搜索有关sa_家族的文档。如果我有一个家庭财产,我将有额外的步骤来确定它映射到sa_家庭
当然,我可以在结构上放置命名良好的getter和setter,例如,
publicshortfamily…
但是,我尝试将互操作结构和方法隐藏在一个更易于使用的接口后面。增加低级互操作定义似乎没有必要。我认为这不应该是个人偏好。如果要将代码移植到另一种语言,则应应用所移植语言的约定
我当然会使用C#约定,因为代码将由C#开发者使用,而不是C/C++开发者,对吗?否则,我们将仍然使用丑陋的\u int32 DWORD
,就像C中的代码一样
以下是一些很好的C#约定指南:
- 为了完整起见,我添加了这个答案。它结合了默特和德格维德回答的要点。下面是一个使用Win32 RECT结构的示例
C/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
}
}
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
}
}
命名空间NetBlast.Runtime.PlatformInvoke.Windows
{
#区域使用
使用制度;
使用System.Collections.Generic;
使用系统图;
使用System.Linq;
使用系统文本;
#端区
///
///Rect(Rect)结构定义矩形的左上角和右下角的坐标。
///
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct Rect:IEquatable、IEquatable、ICloneable
{
#区域常数
#端区
#区域变量
///
///Win32 RECT.left值。
///
私有int左;
///
///Win32 RECT.top值。
///
私人int top;
///
///Win32 RECT.right值。
///
私权;
///
///Win32 RECT.bottom值。
///
私有int底部;
#端区
#区域属性
///
///获取或设置矩形左上角的x坐标。
///
公共Int32左
{
获取{返回this.left;}
设置{this.left=value;}
}
///
///获取或设置矩形左上角的y坐标。
///
公共Int32顶级
{
获取{返回this.top;}
设置{this.top=value;}
}
///
///获取或设置矩形右下角的x坐标。
///
公共Int32权利
{
获取{返回this.right;}
设置{this.right=value;}
}
///
///获取或设置矩形右下角的y坐标。
///
公共Int32底部
{
获取{返回this.bottom;}
设置{this.bottom=value;}
}
///
///获取或设置矩形的高度。
///
公共Int32高度
{
获取{返回this.bottom-this.top;}
设置{this.bottom=value+this.top;}
}
///
///获取或设置矩形的宽度。
///
公共Int32宽度
{
获取{返回this.right-this.left;}
设置{this.right=value+this.left;}
}
///
///获取或设置矩形的左上方位置。
///
公共点位置
{
得到
{
返回新点(this.left,this.top);
}
设置
{
this.right=this.left-value.X;
this.bottom=this.top-value.Y;
此.left=值.X;
this.top=value.Y;
}
}
///
///获取或设置矩形的大小。
///
公共大小
{
得到
{
返回新尺寸(this.Width,this.Height);
}
设置
{
this.right=value.Width+this.left;
this.bottom=value.Height+this.top;
}
}
#端区