Click here to Skip to main content
15,916,941 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello everyone,

I hope you are doing well ?

I would like to share you the following question:

Let's say we start from the following structure used to persist settings already implemented in a previous 32bits application.

C#
public struct struct32bits
{
   [MarshalAs(UnmanagedType.I4)]
   public int lVersionNumber;

   [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
   public string szValue;

   [MarshalAs(UnmanagedType.R4)]
   public float fValue;
}


The objective is to be able to still load the file previously generated based on that format but afterwards convert that structure to a 64bits version.

C#
public struct struct64bits
{
   public Int64 lVersionNumber;
   public string szValue;
   public float fValue;
}


Due to alignment issue, I found a way to loop ove the fields of the structure but when I wanted to assign the value into the new structure, I always got convertion exception.

C#
public static bool Migrate32BitsStructTo64BitsStruct(ref struct32bits st32Bits, ref struct64bits st64Bits)
{
    System.Reflection.FieldInfo[] OldFields = st32Bits.GetType().GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
    System.Reflection.FieldInfo[] NewFields = st64Bits.GetType().GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
    System.Reflection.FieldInfo OldField = null;
    System.Reflection.FieldInfo NewField = null;

    for (int i = 0; i < OldFields.Count(); i++)
    {
        OldField = OldFields[i];
        NewField = NewFields[i];
        if (NewField != null && OldField != null)
        {
            object objValue = OldField.GetValue(st32Bits).ToString();
            try
            {
                object objNewValue = Convert.ChangeType(objValue, NewField.FieldType);
                NewField.SetValue(st64Bits, objNewValue);
            }
            catch (Exception ex)
            {
            }
        }
    }

    return true;
}


I even try with a convertion based on the new type but the assignement exception was still occured.

How would it be possible to apply convertion from 32 to 64 bits structure?

I even tried with the following modification to the structure but this was not solving the issue

C#
public struct struct64bits
{
   public Int64 lVersionNumber {get; set;}
   public string szValue {get; set;}
   public float fValue {get; set;}
}


Does somebody have already tried something like that ?

What implies the 64bits structure manipulation to solve that convertion issue ?

Thank you very much in advance.

Best regards.
MiQi
Posted
Comments
Sergey Alexandrovich Kryukov 20-Nov-12 16:12pm    
Is it binary persistent or text? In both cases, I see no big problem. If this is text, you are moving from smaller to bigger numeric type, so it should work as it is. With binary, the data can take different size, so you will need to preserve "32-bit type" and later do per-member clone to 64-bit. Basically, that's all.
--SA
SuperMiQi 21-Nov-12 4:09am    
Hello Sergey,

Thank you for your answer. The structure is here just basic, I have more fields to define but I wonder why the NewField.SetValue(st64Bits, objNewValue); generates me an exception. This looks to be a very nice way to apply convertion, no ?

Sergey Alexandrovich Kryukov 21-Nov-12 12:43pm    
Again, it all depends on what do you have for serialization...
Do you have to preserve backward compatibility with already serialized data?
--SA
earloc 20-Nov-12 16:59pm    
where do you get what type of exception?
nevertheless, if you have mapping code (Migrate32BitsStructTo64BitsStruct), why do you stick to a solution using reflection rather than copying those three values by hand, like:

struct32bits source;
struct64bits target;
target.lVersionNumber = Convert.ToInt64(source.lVersionNumber);
etc...

(i think, but am not sure, that is what SA suggested?!)
SuperMiQi 21-Nov-12 4:10am    
Hello Earloc,

Thank you for your answer. The structure is here just basic, I have more fields to define but I wonder why the NewField.SetValue(st64Bits, objNewValue); generates me an exception. This looks to be a very nice way to apply convertion, no ?
That would do in an automatic way what you are proposing.

1 solution

i suggest you implement it by hand at first to check if the conversion would generally succeed. When you have this proof of concept you can implement a more generic way using reflection if you prefer this approach. the problem with such solutions is to make sure you match the corresponding fields and do the neccessary value conversions - and reflection is damn slow, so you should implement a mechanism to cache all those FieldInfos (although the performance can be considered less critical, if you deal with only a couple of instances, but thats another story)

if you keep to the reflection-mechanism, this could provide you with a base implementation idea:

C#
private static  IDictionary<string,>    _32BitFieldsDict = null;
private static  IDictionary<string,>    _64BitFieldsDict = null;

private static IDictionary<string,> LoadFieldsFor(Type AIType) {
  //does not filter readonly fields
  var fieldInfos = AIType.GetType().GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);

  var dict = new Dictionary<string,>(fieldInfos.Length);

  foreach (var fieldInfo in fieldInfos) {
    dict.Add(fieldInfo.Name, fieldInfo);
  }

  return dict;
}

public static bool Migrate32BitsStructTo64BitsStruct(ref struct32bits st32Bits, ref struct64bits st64Bits) {

  if (_32BitFieldsDict == null) //not threadsafe
    _32BitFieldsDict = LoadFieldsFor(typeof(struct32bits));

            
  if (_64BitFieldsDict == null) //not threadsafe
    _64BitFieldsDict = LoadFieldsFor(typeof(struct64bits));

  foreach (var source in _32BitFieldsDict) {
    var targetFieldInfo = _64BitFieldsDict[source.Key]; //handle possibility of finding no match
    var sourceFieldInfo = source.Value;

    var sourceValue =sourceFieldInfo.GetValue(st32Bits).ToString();
    var targetValue = Convert.ChangeType(sourceValue, targetFieldInfo.FieldType); //handle conversion problems
    targetFieldInfo.SetValue(st64Bits, targetValue);

    }

  return true;
}
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900