问题
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