如果所有字段都相同,那么将结构复制到类是多么容易

本文关键字:复制 结构 如果 字段 | 更新日期: 2023-09-27 18:17:55

我有这样的struct

public struct InstrumentDefinition2
{
    public int instrumentId;
    public int Decimals;
    public long MinPriceIncrement_Mantissa;
    public short MinPriceIncrement_Exponent;
    public long RoundLot_Mantissa;
    public short RoundLot_Exponent;
    public char MsgType;        // 'd' - Security Definition 'f' - Security Status?
}
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void InstrumentReplayCallback(ref InstrumentDefinition2 value);

它通过委托调用从c++结构体构造而来:

typedef struct _InstrumentDefinition {
    int32_t instrumentId;
    int32_t Decimals;
    int64_t MinPriceIncrement_Mantissa;
    int16_t MinPriceIncrement_Exponent;
    int64_t RoundLot_Mantissa;
    int16_t RoundLot_Exponent;
    char MsgType;        // 'd' - Security Definition 'f' - Security Status
} InstrumentDefinition;

很好。我不确定是否可以将InstrumentDefinition2声明为class。但是我喜欢将InstrumentDefinition2声明为struct,我认为它是关于"指向c++内存块的指针"。

但是在处理过程中,我需要将其复制到一个类中。所以我想声明一个非常相似的C#类:

public class InstrumentDefinition
{
    public int instrumentId;
    public int Decimals;
    public long MinPriceIncrement_Mantissa;
    public short MinPriceIncrement_Exponent;
    public long RoundLot_Mantissa;
    public short RoundLot_Exponent;
    public char MsgType;        // 'd' - Security Definition 'f' - Security Status?
}

问题是我如何将InstrumentDefinition2结构体复制到InstrumentDefinition类?当然,我可以一个一个地分配所有字段,但它会:

  • 我猜相对较慢
  • 容易出错(如果引入了新字段,而我忘记添加它的"复制"怎么办?)

我能在不处理每个字段的情况下做到这一点吗?

如果所有字段都相同,那么将结构复制到类是多么容易

如果您想通过匹配名称来复制类实例的字段或属性值,您可以使用以下代码段:

public void ShallowCopyValues<T1, T2>(T1 firstObject, T2 secondObject)
{
    const BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
    var firstFieldDefinitions = firstObject.GetType().GetFields(bindingFlags);
    IEnumerable<FieldInfo> secondFieldDefinitions = secondObject.GetType().GetFields(bindingFlags);
    foreach (var fieldDefinition in firstFieldDefinitions)
    {
        var matchingFieldDefinition = secondFieldDefinitions.FirstOrDefault(fd => fd.Name == fieldDefinition.Name &&
                                                                                  fd.FieldType == fieldDefinition.FieldType);
        if (matchingFieldDefinition == null)
            continue;
        var value = fieldDefinition.GetValue(firstObject);
        matchingFieldDefinition.SetValue(secondObject, value);
    }
}

这段代码使用反射来确定具有相同名称和相同类型的字段。如果找到匹配项,则更新第二个对象上的值。此外:这段代码比逐个赋值要慢,但这应该无关紧要,因为通常类没有大量字段,这几乎不会导致性能损失。

认为这段代码不完整。在生产代码中,我绝对推荐像Automapper (https://github.com/AutoMapper/AutoMapper#readme)这样的库,它更加灵活和可配置,正如simsim所提到的。

同样,你可以通过相同的布局将c#类映射到c++结构,正如Mathew Watson所提到的。您只需将StructLayoutAttribute应用到类中,就像MSDN上的这个示例所示:http://msdn.microsoft.com/en-us/library/795sy883.aspx重要的是,c#中的类具有与c++中的结构相同的内存布局。

对于自动字段/属性值复制,我会使用Automoapper,值注入器或类似的东西。在您的例子中,使用值注入器复制值看起来像这样:

instrumentDefinition.InjectFrom(instrumentDefinition2);

假设变量名与类名和结构名对应