当对象属性和字典键名不同时,如何将对象/类属性映射到字典?

我正在调用Bloomberg Server API(用于股票市场数据)并将数据恢复到Dictionary其中字典的Key是Bloomberg一侧的Field Name ,该对象包含来自Bloomberg的数据值,可以是stringdecimalDateTimeboolean等。

获得Bloomberg数据后,我需要使用返回的值填充强类型实体/类。 根据我在对bloomberg的请求中发送的字段名称,返回的字典可以具有不同的键值。 我遇到的问题是, bloomberg字段名称和我的.net实体的属性名称不匹配 ,所以我不确定我是否可以使用AutoMapper或类似的库进行此映射。

我也尝试使用Tuple ,其中第一个元组项是bloomberg字段名,第二个元组项是我的实体的属性名,第三个元组项是从bloomberg返回的数据值。 这也没有成功(到目前为止),所以我想知道是否有一种简单的直接方式来维护这个bloombergfield EntityProperty映射并使用相应字段的Bloomberg数据值填充实体的值。 Generic(即使用C#Generics)解决方案会更好!

我已粘贴下面的示例控制台应用程序代码,因此您可以将其粘贴并试用。 2个字典,1个用于stockdata ,其他用于bonddata有假数据,但你明白了。 我还在下面添加了评论来重新迭代我想要完成的任务。

谢谢!!

 namespace MapBBFieldsToEntityProperties { using System; using System.Collections.Generic; class Program { public class StockDataResult { public string Name { get; set; } public decimal LastPrice { get; set; } public DateTime SettlementDate { get; set; } public decimal EPS { get; set; } } public class BondDataResult { public string Name { get; set; } public string Issuer { get; set; } public decimal Duration { get; set; } public DateTime YieldToMaturity { get; set; } } static void Main(string[] args) { // Data Coming from Bloomberg. // Dictionary Key is the Bloomberg Data Field Name. // Dictionary Object is the Value returns and can be any .Net primitive Type // Sample Data returned for a Stock Query to Bloomberg Dictionary dctBloombergStockData = new Dictionary { { "NAME", "IBM" }, { "PX_LAST", 181.30f }, { "SETTLE_DT", "11/25/2013" } // This is Datetime value }; // Sample Data returned for a Bond Query to Bloomberg Dictionary dctBloombergBondData = new Dictionary { { "NAME", "IBM" }, { "ISSUE_ORG","IBM Corp" }, { "DURATION", 4.430f }, { "YLD_TO_M", 6.456f } }; // This is my Stock Entity StockDataResult stockData = new StockDataResult(); // This is my Bond Entity BondDataResult bondData = new BondDataResult(); // PROBLEM STATEMENT: // // Need to somehow Map the Data returned from Bloomberg into the // Corresponding Strong-typed Entity for that Data Type. // ie // map dctBloombergStockData to stockData Entity instance as follows // // dctBloombergStockData."NAME" Key  stockData.Name Property so that // dctBloombergStockData["NAME"] value of "IBM" can be assigned to stockData.Name // // dctBloombergStockData."PX_LAST" Key  stockData.LastPrice Property so that // dctBloombergStockData["PX_LAST"] value 181.30f can be assigned to stockData.LastPrice value. // .... // .. you get the idea. // Similarly, // map dctBloombergBondData Data to bondData Entity instance as follows // // dctBloombergBondData."NAME" Key  bondData.Name Property so that // dctBloombergBondData["NAME"] value of "IBM" can be assigned to bondData.Name property's value // // dctBloombergBondData."ISSUE_ORG" Key  bondData.Issuer Property so that // dctBloombergBondData["ISSUE_ORG"] value 181.30f can be assigned to bondData.Issuer property's value. // // dctBloombergBondData."YLD_TO_M" Key  bondData.YieldToMaturity Property so that // dctBloombergBondData["YLD_TO_M"] value 181.30f can be assigned to bondData.YieldToMaturity property's value. } } } 

我确信可以进行一些改进,但这是指定映射和使用该映射的一种方法。

 class Program { public class Mapper where TEntity : class { private readonly Dictionary> _propertyMappers = new Dictionary>(); private Func _entityFactory; public Mapper ConstructUsing(Func entityFactory) { _entityFactory = entityFactory; return this; } public Mapper Map(Expression> memberExpression, string bloombergFieldName, Expression> converter) { var converterInput = Expression.Parameter(typeof(object), "converterInput"); var invokeConverter = Expression.Invoke(converter, converterInput); var assign = Expression.Assign(memberExpression.Body, invokeConverter); var mapAction = Expression.Lambda>( assign, memberExpression.Parameters[0], converterInput).Compile(); _propertyMappers[bloombergFieldName] = mapAction; return this; } public TEntity MapFrom(Dictionary bloombergDict) { var instance = _entityFactory(); foreach (var entry in bloombergDict) { _propertyMappers[entry.Key](instance, entry.Value); } return instance; } } public class StockDataResult { public string Name { get; set; } public decimal LastPrice { get; set; } public DateTime SettlementDate { get; set; } public decimal EPS { get; set; } } public static void Main(params string[] args) { var mapper = new Mapper() .ConstructUsing(() => new StockDataResult()) .Map(x => x.Name, "NAME", p => (string)p) .Map(x => x.LastPrice, "PX_LAST", p => Convert.ToDecimal((float)p)) .Map(x => x.SettlementDate, "SETTLE_DT", p => DateTime.ParseExact((string)p, "MM/dd/yyyy", null)); var dctBloombergStockData = new Dictionary { { "NAME", "IBM" }, { "PX_LAST", 181.30f }, { "SETTLE_DT", "11/25/2013" } // This is Datetime value }; var myStockResult = mapper.MapFrom(dctBloombergStockData); Console.WriteLine(myStockResult.Name); Console.WriteLine(myStockResult.LastPrice); Console.WriteLine(myStockResult.SettlementDate); } } 

正如你所说的那样,你需要一张映射表。 您可以在类型中创建一个静态只读字典,该字典将从Bloomberg返回的每个键字段映射到强类型类中的属性。

我就是这样做的。 PS:我用linqpad来测试。 PPS:您可以根据需要在字典中添加任意数量的映射器。 您还需要fast-member才能运行此代码。

 void Main() { var dctBloombergStockData = new Dictionary { { "NAME", "IBM" }, { "PX_LAST", 181.30f }, { "SETTLE_DT", "11/25/2013" } // This is Datetime value }; StockDataResult.FromBloombergData(dctBloombergStockData); } // Define other methods and classes here interface IMapper { string PropertyName { get; } object Parse(object source); } class Mapper : IMapper { private Func _parser; public Mapper(string propertyName, Func parser) { PropertyName = propertyName; _parser = parser; } public string PropertyName { get; private set; } public TResult Parse(T source) { source.Dump(); return _parser(source); } object IMapper.Parse(object source) { source.Dump(); return Parse((T)source); } } public class StockDataResult { private static TypeAccessor Accessor = TypeAccessor.Create(typeof(StockDataResult)); private static readonly Dictionary Mappers = new Dictionary(StringComparer.CurrentCultureIgnoreCase){ { "NAME", new Mapper("Name", a => a) }, { "PX_LAST", new Mapper("LastPrice", a => Convert.ToDecimal(a)) }, { "SETTLE_DT", new Mapper("SettlementDate", a => DateTime.ParseExact(a, "MM/dd/yyyy", null)) } }; protected StockDataResult() { } public string Name { get; set; } public float LastPrice { get; set; } public DateTime SettlementDate { get; set; } public decimal EPS { get; set; } public static StockDataResult FromBloombergData(Dictionary state) { var result = new StockDataResult(); IMapper mapper; foreach (var entry in state) { if(!Mappers.TryGetValue(entry.Key, out mapper)) { continue; } Accessor[result, mapper.PropertyName.Dump()] = mapper.Parse(entry.Value); } return result; } } 

怎么样:

 stockData.Name = dctBloombergStockData["NAME"]; stockData.LastPrice = dctBloombergStockData["PX_LAST"] //and so on...