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

C# 如何使用反射将一种类型转换为另一种类型?,c#,.net,visual-studio,c#-4.0,.net-4.0,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 "FromCsvFi

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

有没有一种优雅的方法可以将一种类型复制到另一种类型,而不必手动复制每个成员

更新

以下是一些示例源代码:

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>>IceDateTime,下面是额外的一行代码,其中包括参数ExpirationDate的自定义映射。添加此行可以避免引发异常,因为它不知道如何将日期从一种格式转换为另一种格式

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

例如:

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

例如:

Mapper.CreateMap<FromCsvFile, OptionsEnt >();
return Mapper.Map<FromCsvFile, OptionsEnt>(fromCsvFile);
用类似的东西。它将允许您简单地定义应该映射到FromCsvFile的类OptionsEnt,如果它们具有相同名称和类型的属性,那么您就不需要定义任何其他内容

否则,您必须按属性进行迭代。

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

否则,必须按属性进行迭代。

请参阅。它使用反射的速度稍慢,但有一个优点:您可以更改源代码以处理成员变量需要少量转换的情况

例如,在问题中的示例源代码中,成员变量ExpirationDate在一种类型中为DateTime类型,在另一种类型中为IceDateTime类型。您需要使用扩展名方法.ToDateTime转换日期格式

以下是源代码。有关更多源代码,请参阅:

// 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;
看。它使用反射的速度稍慢,但有一个优点:您可以更改源代码以处理成员变量需要少量转换的情况

例如,在问题中的示例源代码中,成员变量ExpirationDate在一种类型中为DateTime类型,在另一种类型中为IceDateTime类型。您需要使用扩展名方法.ToDateTime转换日期格式

以下是源代码。有关更多源代码,请参阅:

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

你提到按属性迭代,我该怎么做?问题是存在一些特殊情况,例如,ExpirationDate在一种类型中是DateTime类型,在另一种类型中是IceDateTime类型。@Gravitas,您还将在AutoMapper中指定IceDateTime可以映射到常规DateTime,AM将处理这两种类型的属性。您提到“按属性迭代”时,我该怎么做?问题是有一些特殊情况,例如ExpirationDate在一种类型中是DateTime类型,在另一种类型中是IceDateTime类型。@Gravitas,您还将在AutoMapper中指定IceDateTime可以映射到常规DateTime,AM将处理这两种类型的属性。这听起来很棒。然而,它将如何处理角落案件?ExpirationDate在一种类型中为DateTime类型,在另一种类型中为IceDateTime类型。在这些类型之间进行转换很容易,但我猜映射将失败,除非我告诉它使用扩展方法将IceDateTime转换为DateTime.ToDateTime.Aha!找到了:您可以添加自定义类型转换器,请参阅。这听起来很棒。然而,它将如何处理角落案件?ExpirationDate在一种类型中为DateTime类型,在另一种类型中为IceDateTime类型。在这些类型之间进行转换很容易,但我猜映射将失败,除非我告诉它使用扩展方法将IceDateTime转换为DateTime.ToDateTime.Aha!找到了:您可以添加自定义类型转换器,请参阅。Decision on Ox-我真的不想更改映射器的核心源代码来添加自定义映射器。我用AutoMapper来代替它。我决定反对Ox——我真的不想改变映射器的核心源代码来添加我的自定义映射器。我用的是AutoMapper,看,看。