与 C++ 结构等效(或更好)的 C# 结构
Posted
技术标签:
【中文标题】与 C++ 结构等效(或更好)的 C# 结构【英文标题】:Equivalent (or better) C# structures to C++ structures 【发布时间】:2016-10-04 06:21:17 【问题描述】:我是一名转向 C# 的 C++ 程序员(真的很完整)。到目前为止,这是一个非常简单的过渡:)
我正在将一些代码(嗯,重写它)从 C++ 移植到 C#。我对如何移植以下 C++ STL 结构有很多可能性。这是我的 C++ 结构布局的 C++ 代码 sn-p(我没有费心显示枚举以节省混乱,但如果需要,我可以添加):
struct DeviceConnection_t
DeviceType_e device;
DeviceState_e state;
bool isPass;
DeviceConnection_t() :
device(DEV_TYPE_UNKNOWN),
state(DEV_STATE_DISCONNECTED),
isPass(false)
;
struct Given_t
std::string text;
std::vector<DeviceConnection_t> deviceConnections;
;
struct Action_t
ActionEventType_e type;
uint32_t repeat_interval;
uint32_t repeat_duration;
DeviceType_e device;
bool isDone;
Action_t() :
type(AE_TYPE_UNKNOWN),
repeat_interval(0),
repeat_duration(0),
device(DEV_TYPE_UNKNOWN),
isDone(false)
;
struct When_t
std::string text;
std::multimap<uint32_t, Action_t> actions; // time, action
;
所以这里我有一个 DeviceConnection_t 的向量,我在这里读到过:c-sharp-equivalent-of-c-vector-with-contiguous-memory 可以直接变成 C# List<DeviceConnection_t>
。这似乎行得通,到目前为止一切顺利。
接下来是我的multimap<int, Action_t>
,其中 int 是预期/允许重复条目的时间值。
我在这里读到:multimap-in-net 在 C# 中没有等价物,但有各种实现。
所以我可以使用其中一个,但我读到的其他问题如下:order-list-by-date-and-time-in-string-format 让我想到可能有更好的方法来实现我想要的。
我真正想要的是:
1.Action_t
的时间顺序列表 - 其中time
可能是 Action_t 的一个元素(我将它作为我的 c++ 中的一个元素删除,因为它成为我的多映射键)。我还需要能够搜索集合以查找时间值。
2. 某种默认构造函数来填充新实例化结构的默认值,但我也看不出这是如何完成的。
我真的很喜欢 Dictionary
C# 类的外观,但我认为这不符合我目前的任何要求(这里可能有误)。
所以我的两个问题是:
-
创建按时间排序的对象集合的最佳方法是什么?
如何为结构的新实例分配默认值? (与 C++ 中的默认构造函数一样)?
【问题讨论】:
【参考方案1】:通过使用struct
,不可能强制执行初始值。不能提供显式的默认构造函数,并且在默认构造的情况下,所有值都将使用其默认值进行初始化。只能提供额外的构造函数,在这些构造函数中可以初始化字段。在示例中,如果 AE_TYPE_UNKNOWN
和 DEV_TYPE_UNKNOWN
为 0
,那么默认初始化实际上将等同于您的值。
struct Action_t
// example constructor, but there will always be a default constructor
public Action_t(ActionEventType_e type, DeviceType_e device)
this.type = type;
this.device = device;
this.isDone = false;
this.repeat_interval = 0;
this.repeat_duration = 0;
public ActionEventType_e type;
public UInt32 repeat_interval;
public UInt32 repeat_duration;
public DeviceType_e device;
public bool isDone;
如果您需要使用不同于默认值的值强制执行初始化,那么您需要创建一个class
,其中可以进行显式初始化。
class Action_t
public ActionEventType_e type = ActionEventType_e.AE_TYPE_UNKNOWN;
public UInt32 repeat_interval = 0;
public UInt32 repeat_duration = 0;
public DeviceType_e device = DeviceType_e.DEV_TYPE_UNKNOWN;
public bool isDone = false;
但是,为了获得更大的灵活性,我建议使用公共属性,无论是作为自动属性还是作为具有私有支持字段的公共属性。根据您的选择和使用的语言标准版本,您有不同的选项来编写属性和初始化:
class Action_t
public Action_t()
repeat_interval = 0;
public UInt32 repeat_interval get; set;
private UInt32 _repeat_duration = 0;
public UInt32 repeat_duration
get return _repeat_duration;
set _repeat_duration = value;
public bool isDone get; set; = false; // valid for C# 6
您应该阅读 C# 中 struct
和 class
之间的差异,因为作为 C++ 程序员,您可能不会想到一些主要差异,其中 struct
基本上是 public
-default @987654333 @。然后决定struct
是否适合您的情况。
排序多映射的最佳等价物可能是SortedDictionary<key, ICollection<values>>
,它具有处理新键/添加到现有键的添加方法。
IDictionary<DateTime, ICollection<Action_t>> actions = new SortedDictionary<DateTime, ICollection<Action_t>>();
void AddAction(DateTime key, Action_t action)
ICollection<Action_t> values;
if (!actions.TryGetValue(key, out values))
values = new List<Action_t>();
actions[key] = values;
values.Add(action);
【讨论】:
对结构/类的很好的解释和“multimap”的很好的小实现,谢谢+1 :) @code_fodder 关于多重映射的另一个注意事项:C++ 多重映射按插入顺序存储具有相同键的值,并允许每个键重复值。如果您不希望这样,您可以为内部值集合使用不同的类型,例如HashSet<Action_t>
用于每个键的无序唯一值。
是的,这实际上是一个有趣的观点 - 谢谢。我目前的情况并不真正关心被复制的值 - 即同时发生相同的操作是完全有效的:)
我认为您的结构示例不起作用:(。在您的第一个示例中,我收到错误“结构中不能有实例字段初始化程序”。您的第二个示例给出了错误:“结构不能包含显式无参数构造函数”。你确定你的例子是正确的吗?谢谢:)
噢,搞砸了……我在 VS 中编写了代码,它没有即时显示任何错误,但我没有点击最终代码上的编译按钮。我会更新关于初始化的部分。【参考方案2】:
不幸的是,C# 似乎没有排序列表。如果您有键值对,字典就可以了。
1)如果它只是一个集合(列表),你可以看看这里的讨论: Is there a SortedList<T> class in .NET?。否则,您可以手动对集合进行排序(我在示例中将其命名为排序),例如:
actions.Sort((x, y) => x.time.CompareTo(y.time));
在这种情况下,您的时间对象应该是 IComparable 或原语,但您可以将“x.time.CompareTo”替换为任何其他排序方法。 (基于:List<> OrderBy Alphabetical Order)。
如果您使用列表,您可以使用 linq 搜索集合:
actions.First(x=>x.time.certainValue == DesiredValue);
但是有很多函数可以通过树进行搜索。有一些显示:https://msdn.microsoft.com/en-us/library/system.linq.enumerable_methods(v=vs.110).aspx
2) 有多种方法可以做到这一点。首先,默认构造函数:
Action_t()
type=AE_TYPE_UNKNOWN;
repeat_interval=0;
repeat_duration=0;
device= DEV_TYPE_UNKNOWN);
isDone = false;
这与任何其他代码一样工作。但是,如果所有值都是公共属性(也是一个变量:https://msdn.microsoft.com/nl-nl/library/x9fsa0sw.aspx),那么您可以删除构造函数(或拥有一个可以访问的公共构造函数)并使用以下命令创建新实例:
new Action_t
type=AE_TYPE_UNKNOWN,
repeat_interval=0,
repeat_duration=0,
device= DEV_TYPE_UNKNOWN),
isDone = false
不同之处在于变量的设置位置。默认构造函数始终是安全的。
我希望这能回答你的问题!
【讨论】:
+1 用于列表排序的想法——我还想我读到你不能使用这样的构造函数,所以也感谢你澄清这一点——我会试一试:)以上是关于与 C++ 结构等效(或更好)的 C# 结构的主要内容,如果未能解决你的问题,请参考以下文章