从源对象拷贝数据到目标对象
大石头 编写于 2020-08-31 22:24:46
X
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NewLife.Reflection;

namespace NewLife.Data
{
    /// <summary>具有可读性的扩展数据</summary>
    public interface IExtend
    {
        /// <summary>设置 或 获取 数据项</summary>
        /// <param name="key"></param>
        /// <returns></returns>
        Object this[String key] { get; set; }
    }

    /// <summary>具有扩展数据字典</summary>
    public interface IExtend2 : IExtend
    {
        /// <summary>扩展数据键集合</summary>
        IEnumerable<String> Keys { get; }
    }

    /// <summary>具有扩展数据字典</summary>
    public interface IExtend3 : IExtend
    {
        /// <summary>数据项</summary>
        IDictionary<String, Object> Items { get; }
    }

    /// <summary>扩展数据助手</summary>
    public static class ExtendHelper
    {
        /// <summary>名值字典转扩展接口</summary>
        /// <param name="dictionary">字典</param>
        /// <returns></returns>
        public static IExtend ToExtend(this IDictionary<String, Object> dictionary)
        {
            if (dictionary is IExtend ext) return ext;

            return new ExtendDictionary { Items = dictionary };
        }

        /// <summary>扩展接口转名值字典</summary>
        /// <param name="extend">扩展对象</param>
        /// <returns></returns>
        public static IDictionary<String, Object> ToDictionary(this IExtend extend)
        {
            if (extend == null) return null;

            // 泛型字典
            if (extend is IDictionary<String, Object> dictionary) return dictionary;
            if (extend is ExtendDictionary edic) return edic.Items;
            if (extend is IExtend3 ext3) return ext3.Items;

            // IExtend2
            if (extend is IExtend2 ext2)
            {
                var dic = new Dictionary<String, Object>();
                foreach (var item in ext2.Keys)
                {
                    dic[item] = extend[item];
                }
                return dic;
            }

            // 普通字典
            if (extend is IDictionary dictionary2)
            {
                var dic = new Dictionary<String, Object>();
                foreach (DictionaryEntry item in dictionary2)
                {
                    dic[item.Key + ""] = item.Value;
                }
                return dic;
            }

            // 反射 Items
            var pis = extend.GetType().GetProperties(true);
            var pi = pis.FirstOrDefault(e => e.Name == "Items");
            if (pi != null && pi.PropertyType.As<IDictionary<String, Object>>()) return pi.GetValue(extend, null) as IDictionary<String, Object>;

            // 反射属性
            return new ExtendDictionary2 { Data = extend, Keys = pis.Select(e => e.Name).ToList() };

            //var dic2 = new Dictionary<String, Object>();
            //foreach (var item in pis)
            //{
            //    dic2[item.Name] = extend[item.Name];
            //}

            //return dic2;
        }

        /// <summary>从源对象拷贝数据到目标对象</summary>
        /// <param name="target">目标对象</param>
        /// <param name="source">源对象</param>
        public static void Copy(this IExtend target, IExtend source)
        {
            var dst = target.ToDictionary();
            var src = source.ToDictionary();
            foreach (var item in src)
            {
                if (dst.ContainsKey(item.Key)) dst[item.Key] = item.Value;
            }
        }
    }

    /// <summary>扩展字典。引用型</summary>
    public class ExtendDictionary : IExtend, IExtend2, IExtend3
    {
        /// <summary>数据项</summary>
        public IDictionary<String, Object> Items { get; set; }

        IEnumerable<String> IExtend2.Keys => Items?.Keys;

        /// <summary>获取 或 设置 数据</summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public Object this[String item]
        {
            get
            {
                if (Items == null) return null;

                if (Items.TryGetValue(item, out var v)) return v;

                return default;
            }
            set
            {
                if (Items == null) Items = new Dictionary<String, Object>();

                Items[item] = value;
            }
        }
    }

    internal class ExtendDictionary2 : IDictionary<String, Object>
    {
        public IExtend Data { get; set; }

        public ICollection<String> Keys { get; set; }

        public Object this[String key] { get => Data[key]; set => Data[key] = value; }

        public ICollection<Object> Values => Keys.Select(e => Data[e]).ToList();

        public Int32 Count => Keys.Count;

        public Boolean IsReadOnly => false;

        public void Add(String key, Object value) => throw new NotImplementedException();

        public void Add(KeyValuePair<String, Object> item) => throw new NotImplementedException();

        public void Clear() => throw new NotImplementedException();

        public Boolean Contains(KeyValuePair<String, Object> item) => Keys.Contains(item.Key);

        public Boolean ContainsKey(String key) => Keys.Contains(key);

        public void CopyTo(KeyValuePair<String, Object>[] array, Int32 arrayIndex) => throw new NotImplementedException();

        public IEnumerator<KeyValuePair<String, Object>> GetEnumerator()
        {
            foreach (var item in Keys)
            {
                yield return new KeyValuePair<String, Object>(item, Data[item]);
            }
        }

        public Boolean Remove(String key) => throw new NotImplementedException();

        public Boolean Remove(KeyValuePair<String, Object> item) => throw new NotImplementedException();

        public Boolean TryGetValue(String key, out Object value)
        {
            if (Keys.Contains(key))
            {
                value = Data[key];
                return true;
            }
            else
            {
                value = null;
                return false;
            }
        }

        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    }
}