如何使用反射将一种类型转换为另一种?

时间:2011-03-20 11:31:16

标签: c# .net visual-studio c#-4.0 .net-4.0

我有两种非常相似的类型(即成员名称非常相似)。

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

更新

以下是一些示例源代码:

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

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

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

3 个答案:

答案 0 :(得分:3)

也许Automapper

例如:

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

答案 1 :(得分:2)

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

否则你将不得不按属性进行迭代。

答案 2 :(得分: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;