我有一些数据结构,其中包含诸如“Tcpv4Endpoint”之类的信息。和' TCPV6Endpoint'
数据结构是:
[StructLayout(LayoutKind.Sequential)]
public struct MIB_TCPROW_OWNER_PID
{
public uint state;
public uint localAddr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] localPort;
public uint remoteAddr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] remotePort;
public uint owningPid;
}
[StructLayout(LayoutKind.Sequential)]
public struct MIB_TCP6ROW_OWNER_PID
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] localAddr;
public uint localScopeId;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] localPort;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] remoteAddr;
public uint remoteScopeId;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] remotePort;
public uint state;
public uint owningPid;
}
可以想象,我在两个不同的函数中使用这两个数据结构来填充列表视图。我想将这两个结构的添加组合成一个共同的功能。但我无法弄清楚如何在这两个结构之间进行类型转换并访问字段。
我想概括的功能是这样的:
public void addTCPV6ConnectionsToListView()
{
int i;
string strErrorMessage = "";
List<MIB_TCP6ROW_OWNER_PID> tcpRowTable = ...//data populated...//
MIB_TCP6ROW_OWNER_PID row;
//...Error handling case removed for ease of reading ...
ListViewItem[] lItem = new ListViewItem[tcpRowTable.Count];
listView1.BeginUpdate();
for (i = 0; i < tcpRowTable.Count; i++)
{
row = tcpRowTable[i];
lItem[i].Text = Process.GetProcessById((int)row.ProcessId).ProcessName + ".exe";
lItem[i].SubItems.Add(row.ProcessId.ToString());
lItem[i].SubItems.Add("TCPV6");
lItem[i].SubItems.Add("[ " + expandCompressedIPv6Addr(row.LocalAddress.ToString()) + " ]"); //Similiar fields in TCPv4 and TCPv6 structures , except for one or two fields
lItem[i].SubItems.Add(row.LocalPort.ToString());
lItem[i].SubItems.Add("[ " + expandCompressedIPv6Addr(row.RemoteAddress.ToString()) + " ]");
lItem[i].SubItems.Add(row.RemotePort.ToString());
lItem[i].SubItems.Add(getStateInformation(row.State));
}
listView1.Items.AddRange(lItem);
listView1.EndUpdate();
}
是否可以这样做?
答案 0 :(得分:1)
最好的选择是定义一个通用接口。
arr[4]
使用此解决方案,您必须记住,接口只能定义属性,而不能定义字段。因此,您必须将您定义的字段更改为属性:
而不是
public interface MIB_OWNER_PID
{
public uint state {get; set; }
public uint localAddr { get; set; }
public byte[] localPort { get; set; }
public uint remoteAddr { get; set; }
public byte[] remotePort { get; set; }
public uint owningPid { get; set; }
}
写
public uint state;
另一种选择是在使用它们之前简单地将对象强制转换为public uint state { get; set;}
。然后你可以使用任何属性,字段或方法,编译器不会抱怨,因为它们是在运行时进行评估的。因此,如果属性,字段或方法在运行时不存在,您仍将获得异常。
dynamic
答案 1 :(得分:0)
我假设您的specfic [StructLayout]是因为您还希望/需要能够支持memcpy类型的操作。如果是这种情况,您可以在特定字段之前添加方法/属性并与接口结合使用。
public interface MIB_OWNER_PID
{
public void update (uint state,uint localaddr, byte[] localport, /*etc*/)
public uint localAddress { get; set; }
}
[StructLayout(LayoutKind.Sequential)]
public struct MIB_TCPROW_OWNER_PID : MIB_OWNER_PID
{
public uint state;
public uint localAddr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] localPort;
public uint remoteAddr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] remotePort;
public uint owningPid;
public void update (uint state,uint localaddr, byte[] localport, /*etc*/)
{
}
public uint localAddress
{
get { return localAddr;}
set { localAddr = value}
}
}
使用'simple'属性并使用空{get; set;}因为您可能无法控制如何生成支持字段。
在你的结构上使用方法的好处是你可以回复polimorphism以“做正确的事”并实现ipv4和ipv6方式。 (只要方法具有相同的签名。如果你依赖ipv6特定的字段,那么这不能很好地工作)。