c dynamic type and dynamic object creation merge 2 objects map instance

  • 2021-12-05 07:06:17
  • OfStack

This is often the case, We need to process the data when responding to the data requested by the client. For example, the data in the database is int type, which may represent an enumeration or other logical meanings (the design of the database may be considered from the perspective of data security and storage capacity), but the client needs to display its specific meaning.

At this time, our processing mode 1 is generally in 2. If the logic is not complicated and single 1, the data source can be processed by directly modifying the sql statement. At this time, there is no need to deal with anything in the code.

But if the logic complex is a little complicated or the judgment situation has many branches, we have to deal with it from the code point of view. A single object is fine. Multiple objects, such as an list < T > XXX is looped over the fields of an object.

Which led to DTO, The intermediate object of Arg, Of course, I personally like this design very much. But sometimes I am lazy and don't want to write (in most cases, I directly write code generator for mass production). For example, during testing, taking private jobs, and demonstrating, you don't bother to remove dandruff just to quickly present the desired effect. Yes, you will say that there are not many map libraries in the market, such as automap, tinymap, and even the dynamic characteristics rewriting in json. net. Of course, there are many ways, but I don't think it is worthwhile to use a big wheel to do such a small thing. And the bigger the wheel is, the more things it has to do. I don't want to make it so complicated. Well, that's it. I wrote a.

Specific code paste to the following, if you understand, it will be very convenient to expand or modify to their desired effect.


using System.Dynamic;
using System.Reflection;
using System.Collections.Concurrent;

private static readonly ConcurrentDictionary<RuntimeTypeHandle, PropertyInfo[]>
  DynamicObjectProperties = new ConcurrentDictionary<RuntimeTypeHandle, PropertyInfo[]>();

private IDictionary<string, Object> ToDynamicResult<T>(T classobj, Func<string, object, object> injectAct)
  where T : IInjectClass, new()
{
  var type = typeof(T);
  var key = type.TypeHandle;
  var dynamicResult = new ExpandoObject() as IDictionary<string, Object>;

  PropertyInfo[] queryPts = null;
  DynamicObjectProperties.TryGetValue(key, out queryPts);

  if (queryPts == null)
  {
    queryPts = type.GetProperties();
    DynamicObjectProperties.TryAdd(key, queryPts);
  }

  foreach (var p in queryPts)
  {
    var attributes = p.GetCustomAttributes(typeof(IngorePropertyAttribute), true);
    var columnMapping = attributes.FirstOrDefault();
    if (columnMapping != null) continue;

    var _name = p.Name;
    var _value = p.GetValue(classobj, null);
    object _tempvalue = _value;

    if (injectAct != null) _tempvalue = injectAct.Invoke(_name, _value);

    //var value = Convert.ChangeType(value , typeof(string)); 
    dynamicResult.Add(p.Name, _tempvalue);
  }

  return dynamicResult;
}

/// <summary>
///  Object interface supporting dynamic output 
/// </summary>
public interface IInjectClass
{
}
/// <summary>
///  Ignore the attributes of this tag when dynamically outputting 
/// </summary>
public class IngorePropertyAttribute : Attribute
{
}

Let's test one:


 public class kk : IInjectClass
 {
  public string aa { get; set; }
  public int bb { get; set; }
  [IngoreProperty]
  public bool cc { get; set; }
  public DateTime dd { get; set; }
 }kk ist = new kk();
ist.aa = "aaa";
ist.bb = 123;
ist.cc = false;
ist.dd = DateTime.Now;

var tt = ToDynamicResult<kk>(ist, (k, v) =>
{
  if (k != "aa") return v;

  return v + "( Changed oh )";
});

var json = Tools.JsonUtils.JsonSerializer(tt);

json = json + "<br /><br />" + Tools.JsonUtils.JsonSerializer(ToDynamicResult<kk>(
    new kk
    {
      aa = "test",
      bb = 789,
      cc = true,
      dd = DateTime.Now.AddDays(2)
    }, null));

Response.Write(json);

You can reconstruct the properties with parameters or modify the injectAct object to fit your own

Write a test below, and change it into an expression tree. First, the last code


using System;
using System.Linq;
using System.Dynamic;
using System.Reflection;
using System.Linq.Expressions;
using System.Collections.Generic;
using System.Collections.Concurrent;

namespace Tools
{
  public class Class2Map
  {
    private static readonly ConcurrentDictionary<RuntimeTypeHandle, PropertyInfo[]>
      DynamicObjectProperties = new ConcurrentDictionary<RuntimeTypeHandle, PropertyInfo[]>();

    private static PropertyInfo[] GetObjectProperties<T>()
    {
      var type = typeof(T);
      var key = type.TypeHandle;
      PropertyInfo[] queryPts = null;

      DynamicObjectProperties.TryGetValue(key, out queryPts);

      if (queryPts == null)
      {
        queryPts = type.GetProperties();
        DynamicObjectProperties.TryAdd(key, queryPts);
      }

      return queryPts;
    }

    /// <summary>
    ///  Single object mapping 
    /// </summary>
    /// <typeparam name="T"> Type </typeparam>
    /// <param name="source"> Instances </param>
    /// <param name="injectAct">map Method set </param>
    /// <returns> Mapped dynamic object </returns>
    public static IDictionary<string, Object> DynamicResult<T>(T source, params MapCondition[] injectAct)//where T : ICustomMap
    {
      var queryPts = GetObjectProperties<T>();
      var dynamicResult = new ExpandoObject() as IDictionary<string, Object>;

      foreach (var p in queryPts)
      {
        var attributes = p.GetCustomAttributes(typeof(IngoreProperty), true);
        if (attributes.FirstOrDefault() != null) continue;

        var _name = p.Name;           // It turned out to be an attribute name 
        var _value = p.GetValue(source, null); // Original property value 
        object _resultvalue = _value;      // Final mapping value 

        if (injectAct != null)
        {
          string _tempname = null;
          var condition = injectAct.FirstOrDefault(x => x.Orginal == _name);
          if (CheckChangeInfo(condition, out _tempname))
          {
            _resultvalue = condition.fn.Invoke(_value);
            dynamicResult.Add(_tempname ?? _name, _resultvalue);
            continue;
          }
        }

        //var value = Convert.ChangeType(value , typeof(string)); 
        dynamicResult.Add(_name, _resultvalue);
      }

      return dynamicResult;
    }

    /// <summary>
    ///  Merge 2 Objects 
    /// </summary>
    /// <typeparam name="TSource"> Object 1 Type </typeparam>
    /// <typeparam name="TTarget"> Object 2 Type </typeparam>
    /// <param name="s"> Object 1 Instances </param>
    /// <param name="t"> Object 2 Instances </param>
    /// <returns> Merged dynamic objects </returns>
    public static IDictionary<string, Object> MergerObject<TSource, TTarget>(TSource s, TTarget t)
    {
      var targetPts = GetObjectProperties<TSource>();

      PropertyInfo[] mergerPts = null;
      var _type = t.GetType();
      mergerPts = _type.Name.Contains("<>") ? _type.GetProperties() : GetObjectProperties<TTarget>();

      var dynamicResult = new ExpandoObject() as IDictionary<string, Object>;

      foreach (var p in targetPts)
      {
        var attributes = p.GetCustomAttributes(typeof(IngoreProperty), true);
        if (attributes.FirstOrDefault() != null) continue;

        dynamicResult.Add(p.Name, p.GetValue(s, null));
      }
      foreach (var p in mergerPts)
      {
        var attributes = p.GetCustomAttributes(typeof(IngoreProperty), true);
        if (attributes.FirstOrDefault() != null) continue;

        dynamicResult.Add(p.Name, p.GetValue(t, null));
      }

      return dynamicResult;
    }
    /// <summary>
    ///  Merge 2 Objects 
    /// </summary>
    /// <typeparam name="TSource"> Object 1 Type </typeparam>
    /// <typeparam name="TTarget"> Object 2 Type </typeparam>
    /// <param name="s"> Object 1 Instances </param>
    /// <param name="t"> Object 2 Instances </param>
    /// <returns> Merged dynamic objects </returns>
    public static List<IDictionary<string, Object>> MergerListObject<TSource, TTarget>(List<TSource> s, TTarget t)
    {
      var targetPts = GetObjectProperties<TSource>();

      PropertyInfo[] mergerPts = null;
      var _type = t.GetType();
      mergerPts = _type.Name.Contains("<>") ? _type.GetProperties() : GetObjectProperties<TTarget>();

      var result = new List<IDictionary<string, Object>>();

      s.ForEach(x =>
      {
        var dynamicResult = new ExpandoObject() as IDictionary<string, Object>;

        foreach (var p in targetPts)
        {
          var attributes = p.GetCustomAttributes(typeof(IngoreProperty), true);
          if (attributes.FirstOrDefault() != null) continue;

          dynamicResult.Add(p.Name, p.GetValue(x, null));
        }

        foreach (var p in mergerPts)
        {
          var attributes = p.GetCustomAttributes(typeof(IngoreProperty), true);
          if (attributes.FirstOrDefault() != null) continue;

          dynamicResult.Add(p.Name, p.GetValue(t, null));
        }

        result.Add(dynamicResult);
      });

      return result;
    }

    private static bool CheckChangeInfo(MapCondition condition, out string name)
    {
      name = null;

      bool result = condition != null &&
             condition.fn != null &&
             !string.IsNullOrWhiteSpace(condition.Orginal);//&&
            //!string.IsNullOrWhiteSpace(condition.NewName);

      if (result)
      {
        var temp = condition.NewName;
        name = (string.IsNullOrWhiteSpace(temp) || temp.Trim().Length == 0) ? null : temp;
      }

      return result;
    }
  }
}

Under Test 1:


List<KeyValue> kk = new List<KeyValue> 
{ 
  new KeyValue{key="aaa", value="111"},
  new KeyValue{key="bbb", value="222"},
  new KeyValue{key="ccc", value="333"},
  new KeyValue{key="ddd", value="444"},
};

var result = Class2Map.MergerListObject<KeyValue, dynamic>(kk, new { p = "jon test" });
var json = JsonUtils.JsonSerializer(result);

Response.Write(json);

The output is as follows:


[{"key":"aaa","value":"111","p":"jon test"},{"key":"bbb","value":"222","p":"jon test"},{"key":"ccc","value":"333","p":"jon test"},{"key":"ddd","value":"444","p":"jon test"}]

var result = Class2Map.MergerObject<KeyValue, dynamic>(
        new KeyValue { key = "aaa", value = "111" },
        new { p = "jon test" }
      );
var json = JsonUtils.JsonSerializer(result);

Response.Write(json);

The output is as follows:


{ "key": "aaa", "value": "111", "p": "jon test" }


Related articles: