与 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&lt;DeviceConnection_t&gt;。这似乎行得通,到目前为止一切顺利。

接下来是我的multimap&lt;int, Action_t&gt;,其中 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_UNKNOWNDEV_TYPE_UNKNOWN0,那么默认初始化实际上将等同于您的值。

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# 中 structclass 之间的差异,因为作为 C++ 程序员,您可能不会想到一些主要差异,其中 struct 基本上是 public-default @987654333 @。然后决定struct 是否适合您的情况。


排序多映射的最佳等价物可能是SortedDictionary&lt;key, ICollection&lt;values&gt;&gt;,它具有处理新键/添加到现有键的添加方法。

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&lt;Action_t&gt; 用于每个键的无序唯一值。 是的,这实际上是一个有趣的观点 - 谢谢。我目前的情况并不真正关心被复制的值 - 即同时发生相同的操作是完全有效的:) 我认为您的结构示例不起作用:(。在您的第一个示例中,我收到错误“结构中不能有实例字段初始化程序”。您的第二个示例给出了错误:“结构不能包含显式无参数构造函数”。你确定你的例子是正确的吗?谢谢:) 噢,搞砸了……我在 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# 结构的主要内容,如果未能解决你的问题,请参考以下文章

如何将 System::^array 从 C# 函数转换为 C++ 中的等效数据类型

是否可以单步执行 C++ 结构的成员?

在构建时将 C++ 结构转换为 C# 结构

C++ 到 C# 回调结构编组

C 编程语言等效于 C++ 中的结构初始化

C ++中复杂结构的python 3中的等效数据结构