如果所有字段都相同,如何轻松地将struct复制到类中?

时间:2013-06-12 09:10:44

标签: c#

我有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类?当然,我可以逐个分配所有字段,但它会:

  • 我觉得比较慢
  • 容易出错(如果引入了新字段,我忘了添加“应对”怎么办?)

那么,如果不应对每一个领域,我能以某种方式做到这一点吗?

2 个答案:

答案 0 :(得分:3)

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

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 ++中相同的内存布局。

答案 1 :(得分:0)

对于自动字段/属性值复制,我使用AutomoapperValue injecter或类似的东西。 在您的情况下,使用值injecter复制值将如下所示:

instrumentDefinition.InjectFrom(instrumentDefinition2);

假设变量名对应于类和结构名。