如何映射对象/类属性到字典时对象属性和字典键名不同? [英] How to Map Object / Class Property to Dictionary When Object Property And Dictionary Key Names Are Different?

查看:711
本文介绍了如何映射对象/类属性到字典时对象属性和字典键名不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我打电话彭博服务器API(在股市中的数据),并在获取数据回词典<字符串对象> 到字典是字段名称在Bloomberg的一侧,对象包含从彭博资讯的数据值,可以是字符串小数的DateTime 布尔



在我得到了彭博社的数据,我需要填充我的强类型实体/使用值类返回。根据什么字段名称我在请求发送彭博,返回的字典可以有不同的键值。我遇到的问题是,彭博字段名和我的.NET实体的属性名称不匹配,所以我不知道我能做到用这种映射 AutoMapper 或类似的库



我使用也尝试了元组LT;字符串,字符串对象> 其中第一元组产品彭博字段名,第二元组产品我的实体的属性名和第3元组产品从Bloomberg返回的数据值。这是不工作或者(到目前为止),所以我想知道是否有维护这个bloombergfield℃的简单直接的方式; - > EntityProperty映射和填充使用彭博的数据价值的各个领域实体的价值。一个通用的(即使用C#泛型)解决方案将更加美好!



我已经粘贴下面的示例控制台应用程序代码,这样你就可以粘贴和尝试。 2.字典,1 stockdata 等为 bonddata 有伪造数据,但你的想法。我还增加了下面的评论再次重申什么,我试图完成。



谢谢!



 命名空间MapBBFieldsToEntityProperties 
{使用系统
;
使用System.Collections.Generic;

类节目
{
公共类StockDataResult
{
公共字符串名称{;组; }
公共小数LastPrice {搞定;组; }
公众的DateTime SettlementDate {搞定;组; }
公共小数EPS {搞定;组; }

}

公共类BondDataResult
{
公共字符串名称{;组; }
公共字符串发行人{搞定;组; }
公共小数持续时间{搞定;组; }
公众的DateTime YieldToMaturity {搞定;组; }
}


静态无效的主要(字串[] args)
{

//数据从Bloomberg到来。
//字典的关键是彭博社的数据字段名称。
// Dictionary对象的价值回报,可以是任何.NET基本类型

//样本数据返回一个股票查询彭博
字典<字符串对象> dctBloombergStockData
=新词典<字符串对象>
{
{姓名,IBM},
{PX_LAST,181.30f}
{SETTLE_DT,2013年11月25日} / /这是datetime值
};

//样本数据返回邦德查询彭博
&字典LT;字符串对象> dctBloombergBondData =
新字典<字符串对象>
{
{姓名,IBM},
{ISSUE_ORG,IBM公司},
{持续时间,4.430f}
{YLD_TO_M,6.456f}
};

//这是我的股票实体
StockDataResult stockData =新StockDataResult();

//这是我的邦德实体
BondDataResult bondData =新BondDataResult();

//问题陈述:
//
//需要以某种方式地图中的数据从彭博信息返回到
//对应的强类型的实体为该数据类型。
//即
//映射到dctBloombergStockData实体stockData实例如下
//
// dctBloombergStockData姓名键<&-------- GT ; stockData.Name属性,以便IBM的那个
// dctBloombergStockData [NAME]值可以被分配到stockData.Name
//
// dctBloombergStockDataPX_LAST键< --------> stockData.LastPrice属性,以便
// dctBloombergStockData [PX_LAST]值181.30f可以被分配到stockData.LastPrice值。
// ...
// ..你的想法。
//同样,
// dctBloombergBondData数据映射到bondData Entity实例如下
//
// dctBloombergBondData姓名键< ------- - > bondData.Name属性,以便IBM的那个
// dctBloombergBondData [NAME]值可以被分配到bondData.Name属性的值
//
// dctBloombergBondData。ISSUE_ORG键<&-------- GT; bondData.Issuer属性,以便
// dctBloombergBondData [ISSUE_ORG]值181.30f可以被分配到bondData.Issuer属性的值。
//
// dctBloombergBondDataYLD_TO_M键<&-------- GT; bondData.YieldToMaturity属性,以便
// dctBloombergBondData [YLD_TO_M]值181.30f可以被分配到bondData.YieldToMaturity属性的值。
}
}
}


解决方案

我确信不少改进是可能的,但是这是指定的映射,并使用该地图的一种方法

 类节目
{
公共类映射器LT; TEntity>其中,TEntity:类
{
私人只读字典<字符串,动作< TEntity,对象>> _propertyMappers =新词典<字符串,动作< TEntity,对象>>();
私人Func键< TEntity> _entityFactory;

公共映射器LT; TEntity> ConstructUsing(Func键< TEntity> entityFactory)
{
_entityFactory = entityFactory;
返回这一点;
}

公共映射器LT; TEntity>地图< TProperty>(表达式来; Func键< TEntity,TProperty>> memberExpression,串bloombergFieldName,表达< Func键<对象,TProperty>>转换器)
{
VAR converterInput = Expression.Parameter(typeof运算(对象),converterInput);
VAR invokeConverter = Expression.Invoke(变频器,converterInput);
VAR分配= Expression.Assign(memberExpression.Body,invokeConverter);
变种地图行动= Expression.Lambda<作用&下; TEntity,对象>>(
分配,memberExpression.Parameters [0],converterInput).Compile();
_propertyMappers [bloombergFieldName] =地图行动;
返回这一点;
}

公共TEntity MapFrom(词典<字符串对象> bloombergDict)
{
无功实例= _entityFactory();
的foreach(在bloombergDict VAR的条目)
{
_propertyMappers [entry.Key(例如,entry.Value);
}
返回实例;
}
}

公共类StockDataResult
{
公共字符串名称{;组; }
公共小数LastPrice {搞定;组; }
公众的DateTime SettlementDate {搞定;组; }
公共小数EPS {搞定;组; }
}

公共静态无效的主要(PARAMS字串[] args)
{
变种映射器=新映射器LT; StockDataResult>()
.ConstructUsing (()=>新建StockDataResult())b .MAP $ b $(X => x.Name,NAME,p =>(字符串)p)
.MAP(X => x.LastPrice,PX_LAST,p => Convert.ToDecimal((浮点)p))
.MAP(X => x.SettlementDate,SETTLE_DT,p => DateTime.ParseExact((字符串)p,MM / DD / YYYY,NULL));


变种dctBloombergStockData =新词典<字符串对象>
{
{姓名,IBM},
{PX_LAST,181.30f}
{SETTLE_DT,2013年11月25日} / /这是datetime值
};
VAR myStockResult = mapper.MapFrom(dctBloombergStockData);

Console.WriteLine(myStockResult.Name);
Console.WriteLine(myStockResult.LastPrice);
Console.WriteLine(myStockResult.SettlementDate);
}
}


I am calling Bloomberg Server API (for Stock Market Data) and getting Data back in a Dictionary<string, object> Where the Key to the dictionary is the Field Name on Bloomberg's side, and the object contains the data value from Bloomberg and can be string, decimal, DateTime, boolean etc.

After I get the Bloomberg Data, I need to populate my strong type entities / classes with the values returned. Depending on what Field Names I send in my request to bloomberg, the returned Dictionary could have different key values. The problem I am having is, the bloomberg field name and my .net entity's property names don't match, so I am not sure I can do this mapping using AutoMapper or a similar library.

I also tried using a Tuple<string,string,object> where the 1st tuple item is the bloomberg field name, the 2nd tuple item is my entity's property name and the 3rd tuple item is the data value returned from bloomberg. That is not working out either (so far), so I am wondering if there is a simple straight-forward way of maintaining this bloombergfield<-->EntityProperty mapping and populate the Entity's value using the Bloomberg Data Value for the respective field. A Generic (i.e. using C# Generics) solution would be even better!

I have pasted below sample console app code so you can paste it and try it out. The 2 dictionaries, 1 for stockdata and other for bonddata have fake data, but you get the idea. I have also added comments below to re-iterate what I am trying to accomplish.

Thanks!!

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<string, object> dctBloombergStockData 
                = new Dictionary<string, object>
                            {
                                { "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<string, object> dctBloombergBondData = 
                new Dictionary<string, object>
                            {
                                { "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.
            // i.e. 
            // 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.                                
        }
    }
}

解决方案

I am sure quite a few improvements are possible, but this is one way of specifying a mapping and using that map.

class Program
{
    public class Mapper<TEntity> where TEntity : class
    {
        private readonly Dictionary<string, Action<TEntity, object>> _propertyMappers = new Dictionary<string, Action<TEntity, object>>();
        private Func<TEntity> _entityFactory;

        public Mapper<TEntity> ConstructUsing(Func<TEntity> entityFactory)
        {
            _entityFactory = entityFactory;
            return this;
        }

        public Mapper<TEntity> Map<TProperty>(Expression<Func<TEntity, TProperty>> memberExpression, string bloombergFieldName, Expression<Func<object, TProperty>> 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<Action<TEntity, object>>(
                assign, memberExpression.Parameters[0], converterInput).Compile();
            _propertyMappers[bloombergFieldName] = mapAction;
            return this;
        }

        public TEntity MapFrom(Dictionary<string, object> 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<StockDataResult>()
            .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<string, object>
        {
            { "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);
    }
}

这篇关于如何映射对象/类属性到字典时对象属性和字典键名不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆