private static void ExtractProperties <K>(IEnvContext <K> context, Type extractObjType, object extractObj)
        {
            List <PropertyInfo> properties = cachedTypePropertyDic[extractObjType][ContextUsage.Out];

            if (properties != null && properties.Count > 0)
            {
                foreach (var property in properties)
                {
                    if (typeof(IEnvContext <>).IsAssignableFrom(property.PropertyType))
                    {
                        throw new InvalidOperationException("Context can only be used with the InjectUsage.In option.");
                    }

                    var attr = property.GetCustomAttribute <ContextFieldAttribute>();

                    object fieldValue = property.GetValue(extractObj);
                    if (!attr.Optional)
                    {
                        context.AddOrUpdate((K)attr.Key, fieldValue);
                    }
                    else if (fieldValue != null)
                    {
                        context.AddOrUpdate((K)attr.Key, fieldValue);
                    }
                }
            }
        }
        private static void InjectProperties <K>(IEnvContext <K> context, Type injectObjType, object injectObj)
        {
            List <PropertyInfo> properties = cachedTypePropertyDic[injectObjType][ContextUsage.Out];

            if (properties != null && properties.Count > 0)
            {
                foreach (var property in properties)
                {
                    var attr = property.GetCustomAttribute <ContextFieldAttribute>();

                    if (!context.TryGet((K)attr.Key, out object fieldValue))
                    {
                        if (fieldValue == null && !attr.Optional)
                        {
                            throw new Exception($"ContextUtil::Inject->Data not found.fieldName = {property.Name},key = {attr.Key}");
                        }
                    }
                    property.SetValue(injectObj, fieldValue);
                }
            }
        }
        private static void InjectFields <K>(IEnvContext <K> context, Type injectObjType, object injectObj)
        {
            List <FieldInfo> fields = cachedTypeFieldDic[injectObjType][ContextUsage.In];

            if (fields != null && fields.Count > 0)
            {
                foreach (var field in fields)
                {
                    var attr = field.GetCustomAttribute <ContextFieldAttribute>();

                    if (!context.TryGet((K)attr.Key, out object fieldValue))
                    {
                        if (fieldValue == null && !attr.Optional)
                        {
                            throw new Exception($"ContextUtil::Inject->Data not found.fieldName = {field.Name},key = {attr.Key}");
                        }
                    }
                    field.SetValue(injectObj, fieldValue);
                }
            }
        }
        public static void Inject <K>(IEnvContext <K> context, object injectObj)
        {
            if (injectObj == null || context == null)
            {
                throw new ArgumentNullException("ContextUtil::Inject->argument is null.");
            }
            Type injectObjType = injectObj.GetType();

            if (!cachedTypeFieldDic.ContainsKey(injectObjType))
            {
                CachedFields(injectObjType);
            }

            if (!cachedTypePropertyDic.ContainsKey(injectObjType))
            {
                CachedProperties(injectObjType);
            }

            InjectFields(context, injectObjType, injectObj);
            InjectProperties(context, injectObjType, injectObj);
        }
        public static void Extract <K>(IEnvContext <K> context, object extractObj)
        {
            if (extractObj == null || context == null)
            {
                throw new ArgumentNullException("ContextUtil::Extract->argument is null");
            }

            Type extractObjType = extractObj.GetType();

            if (!cachedTypeFieldDic.ContainsKey(extractObjType))
            {
                CachedFields(extractObjType);
            }

            if (!cachedTypePropertyDic.ContainsKey(extractObjType))
            {
                CachedProperties(extractObjType);
            }

            ExtractFields(context, extractObjType, extractObj);
            ExtractProperties(context, extractObjType, extractObj);
        }