How to convert one type to another using reflection?

烈酒焚心 提交于 2020-01-30 08:25:31

问题


I have a two types that are very similar (i.e. the member names are very similar).

Is there an elegant way to copy one type to another, without having to copy each individual member by hand?

Update

Here is some sample source code:

main()
{
  FromCsvFile x = new FromCsvFile(fileName);
  OptionsEnt y = x.ToOptionsEnt(); // See helper function below.
}

// Chained helper function to convert type "FromCsvFile" to type "OptionsEnt".
// Want to replace this with something more elegant (perhaps with reflection?).
// Notice the corner cases, i.e. the "ExpirationDate" is a special conversion.
public static OptionsEnt ToOptionsEnt(this FromCsvFile fromCsvFile)
{
  return new OptionsEnt
           {
             Last = fromCsvFile.Last,
             Ask = fromCsvFile.Ask,
             Bid = fromCsvFile.Bid,
             Delta = fromCsvFile.Delta,
             EODsnapshotNewYorkTime = fromCsvFile.EODsnapshotNewYorkTime,
             Exchange = fromCsvFile.Exchange,
             ExpirationDate = fromCsvFile.Expiration.ToTypeIceDate(),
             Gamma = fromCsvFile.Gamma,
             IV = fromCsvFile.IV,
             LastDate = fromCsvFile.Date.ToTypeIceDate(),
             AdjustedStockClose = fromCsvFile.AdjustedStockClose,
             MeanPrice = fromCsvFile.MeanPrice,
             OptionType = fromCsvFile.OptionType == "C" ? OptionTypeEnum.enCall : OptionTypeEnum.enPut,
             OpenInterest = fromCsvFile.OpenInterest,
             Rho = fromCsvFile.Rho,
             StockSymbol = fromCsvFile.SymbolStock,
             StrikePrice = fromCsvFile.StrikePrice,
             Symbol = fromCsvFile.Symbol,
             StockPriceForIV = fromCsvFile.StockPriceForIV,
             Star = fromCsvFile.Star,
             Theta = fromCsvFile.Theta,
             Vega = fromCsvFile.Vega,
             Volume = fromCsvFile.Volume,
             IVnotInterpolated = fromCsvFile.IVnotInterpolated
          };
}

Update

Decided to go with AutoMapper.

Here is the code that replaces all of the code above (assuming that all member names are of the same name and type):

main()
{
  FromCsvFile x = new FromCsvFile(fileName);
  OptionsEnt y = Mapper.Map<FromCsvFile, OptionsEnt>(x);
}

As we need some custom converters (i.e. DateTime >> IceDateTime), here is the extra line of code that includes a custom mapping for the parameter "ExpirationDate". Adding this line avoids an exception being thrown as it doesn't know how to convert dates from one format to another.

 Mapper.CreateMap<DateTime, typeIceDate>().ConvertUsing(ConverterIceTypeIceDate.ToTypeIceDate);

回答1:


Maybe Automapper?

For example:

Mapper.CreateMap<FromCsvFile, OptionsEnt >();
return Mapper.Map<FromCsvFile, OptionsEnt>(fromCsvFile);



回答2:


Use something like AutoMapper for that. It will allow you to simply define that class OptionsEnt should be mapped to FromCsvFile and if they have the properties with same names and types then you won't need to define anything else.

Otherwise you'll have to iterate by properties.




回答3:


See Copyable: A framework for copying or cloning .NET objects. Its slightly slower (it uses reflection), but it has one advantage: you can alter the source to handle corner cases where the member variables need a little bit of work to convert.

For example, in the sample source code in the question, member variable "ExpirationDate" is of type "DateTime" in one type, and type "IceDateTime" in the other (you need to convert the date format with the extension method .ToDateTime).

Here is the source (see the original blog entry for more source):

// Modification to original source code.
Type type = instance.GetType();

if (instance.GetType().Name == "DataTable")
{
    // Added to handle custom type.
    DataTable dt = (DataTable)instance;
    copy = dt.Copy();
}
else if (instance.GetType().Name == "DataSet")
{
    // Added to handle custom type.
    DataSet ds = (DataSet)instance;
    copy = ds.Copy();
}
else
{
    // This is the original source.
    while (type != null)
    {
        foreach (FieldInfo field in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
        {
            object value = field.GetValue(instance);
            if (visited.ContainsKey(value))
                field.SetValue(copy, visited[value]);
            else
                field.SetValue(copy, value.Clone(visited));
        }
        type = type.BaseType;
    }
}
return copy;


来源:https://stackoverflow.com/questions/5368200/how-to-convert-one-type-to-another-using-reflection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!