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,看,看。