【问题标题】:Equivalent (or better) C# structures to C++ structures与 C++ 结构等效(或更好)的 C# 结构
【发布时间】: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# 类的外观,但我认为这不符合我目前的任何要求(这里可能有误)。

所以我的两个问题是:

  1. 创建按时间排序的对象集合的最佳方法是什么?
  2. 如何为结构的新实例分配默认值? (与 C++ 中的默认构造函数一样)?

【问题讨论】:

    标签: c# c++ data-structures


    【解决方案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 用于列表排序的想法——我还想我读到你不能使用这样的构造函数,所以也感谢你澄清这一点——我会试一试:)
    猜你喜欢
    • 2011-07-18
    • 2011-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-23
    相关资源
    最近更新 更多