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

时间:2022-09-24 19:04:40

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.

决定使用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.

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

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

3 个解决方案

#1


3  

Maybe Automapper?

也许Automapper?

For example:

例如:

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

#2


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.

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

Otherwise you'll have to iterate by properties.

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

#3


0  

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.

请参阅可复制:用于复制或克隆.NET对象的框架。它稍慢(它使用反射),但它有一个优点:你可以改变源来处理成员变量需要一点工作来转换的极端情况。

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).

例如,在问题的示例源代码中,成员变量“ExpirationDate”在一种类型中的类型为“DateTime”,在另一种类型中键入“IceDateTime”(您需要使用扩展方法.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;

#1


3  

Maybe Automapper?

也许Automapper?

For example:

例如:

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

#2


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.

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

Otherwise you'll have to iterate by properties.

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

#3


0  

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.

请参阅可复制:用于复制或克隆.NET对象的框架。它稍慢(它使用反射),但它有一个优点:你可以改变源来处理成员变量需要一点工作来转换的极端情况。

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).

例如,在问题的示例源代码中,成员变量“ExpirationDate”在一种类型中的类型为“DateTime”,在另一种类型中键入“IceDateTime”(您需要使用扩展方法.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;