2011-03-20 91 views
1

我有两个非常相似的类型(即成员名称非常相似)。如何使用反射将一种类型转换为另一种类型?

是否有一种优雅的方式将一种类型复制到另一种类型,而无需手动复制每个单独的成员?

更新

下面是一些示例代码:

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 
      }; 
} 

更新

决定去AutoMapper。

下面是替换上面的代码中所有代码(假定所有成员名称相同的名称和类型):

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

,因为我们需要一些自定义的转换器(即日期时间>> IceDateTime),这里是额外的代码行,包括参数“ExpirationDate”的自定义映射。添加此行可以避免抛出异常,因为它不知道如何将日期从一种格式转换为另一种格式。

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

参见http://stackoverflow.com/questions/870656/object-to-object-mapping-utility。 – Contango 2011-03-20 11:51:07

回答

3

也许Automapper

例如:

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

这听起来不错。但是,它将如何处理角落案件? ExpirationDate是一种类型的DateTime类型,在另一种类型中输入IceDateTime。它很容易在这些类型之间进行转换 - 但我想映射将失败,除非我告诉它“使用扩展方法.ToDateTime将IceDateTime转换为DateTime”。 – Contango 2011-03-20 12:17:58

+1

啊哈!找到它:您可以添加自定义类型转换器,请参阅http://automapper.codeplex.com/wikipage?title=Custom%20Type%20Converters&referringTitle=Home。 – Contango 2011-03-20 12:34:08

+0

你明白了:) – svrist 2011-03-20 16:04:02

2

使用类似AutoMapper了点。它将允许你简单地定义类OptionsEnt应映射到FromCsvFile,如果它们具有相同名称和类型的属性,则不需要定义其他任何内容。

否则,你将不得不迭代的属性。

+0

你提到“由专家迭代”我该怎么做?问题是有一些角落案件,即ExpirationDate是一种类型的“DateTime”类型,另一种类型是“IceDateTime”。 – Contango 2011-03-20 12:03:08

+0

@Gravitas,您还将在AutoMapper中指定“IceDateTime”可以映射到常规的“DateTime”,AM将处理这两种类型的属性。 – Snowbear 2011-03-20 12:31:16

+0

不错 - 谢谢!现在一切都很完美。 – Contango 2011-03-22 09:28:45

0

请参阅Copyable: A framework for copying or cloning .NET objects。它稍慢(它使用反射),但它有一个好处:你可以改变源来处理成员变量需要一点工作来转换的角落情况。

例如,在问题的示例源代码中,成员变量“ExpirationDate”的类型是“DateTime”,而在另一个类型中输入“IceDateTime”(您需要将日期格式转换为扩展名方法.ToDateTime)。

这里是源(见original blog entry为多个源):

// 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; 
+0

决定对牛 - 我不是真的想改变映射器的核心源代码来添加我的自定义映射器。我使用的是AutoMapper。 – Contango 2011-03-21 09:40:38

相关问题