///<summary>
        /// 키 및 culture에 대한 리소스 개체를 반환합니다.
        ///</summary>
        ///<returns>
        ///<paramref name="resourceKey" /> 및 <paramref name="culture" />에 대한 리소스 값을 포함하는 <see cref="T:System.Object" />입니다.
        ///</returns>
        ///<param name="resourceKey">
        /// 특정 리소스를 식별하는 키입니다.
        /// </param>
        ///<param name="culture">
        /// 리소스의 지역화된 값을 식별하는 culture입니다.
        ///</param>
        /// <returns>resource value, if not exists, return null</returns>
        public override object GetObject(string resourceKey, CultureInfo culture) {
            if(IsDebugEnabled)
                log.Debug(@"리소스 값을 조회합니다. resourceKey=[{0}], culture=[{1}]", resourceKey, culture);

            culture = culture.GetCulture();
            var result = base.GetObject(resourceKey, culture);

            // resource value가 문자열일때만 parameter를 치환한다.
            //
            if(result != null && result is string && ((string)result).Contains(StringResourceTool.PARAM_REF_START))
                result = GetExpanded(resourceKey, culture, (string)result);

            if(IsDebugEnabled)
                log.Debug("리소스 값을 조회했습니다. resourceKey=[{0}], culture=[{1}], value=[{2}]", resourceKey, culture, result);

            return result;
        }
        /// <summary>
        /// 리소스 값 얻기
        /// </summary>
        public string GetResource(CultureInfo culture, string resourceKey) {
            if(IsDebugEnabled)
                log.Debug("리소스 얻기... resourceType=[{0}], culture=[{1}], resourceKey=[{2}]", ResourceName, culture, resourceKey);

            string resourceValue;

            try {
                culture = culture.GetCulture();

                // 지정된 문화권에 해당 키가 정의되어 있지 않다면, 상위 문화권에서 찾는다.
                //
                resourceValue = GetResourceInternal(culture, resourceKey);
            }
            catch(Exception ex) {
                if(log.IsWarnEnabled) {
                    log.Warn("리소스를 얻는데 실패했습니다. 예외를 발생시키지는 않고, 빈 문자열을 반환합니다. culture=[{0}], resourceKey=[{1}", culture, resourceKey);
                    log.Warn(ex);
                }
                resourceValue = string.Empty;
            }

            if(IsDebugEnabled)
                log.Debug("리소스를 얻었습니다. resourceType=[{0}], culture=[{1}], resourceKey=[{2}], resourceValue=[{3}]",
                          ResourceName, culture, resourceKey, resourceValue);

            return resourceValue;
        }
        ///<summary>
        /// 키 및 culture에 대한 리소스 개체를 반환합니다.
        ///</summary>
        ///<returns>
        ///<paramref name="resourceKey" /> 및 <paramref name="culture" />에 대한 리소스 값을 포함하는 <see cref="T:System.Object" />입니다.
        ///</returns>
        ///<param name="resourceKey">
        /// 특정 리소스를 식별하는 키입니다.
        /// </param>
        ///<param name="culture">
        /// 리소스의 지역화된 값을 식별하는 culture입니다.
        ///</param>
        /// <returns>resource value, if not exists, return null</returns>
        public override object GetObject(string resourceKey, CultureInfo culture) {
            resourceKey.ShouldNotBeWhiteSpace("resourceKey");

            if(IsDebugEnabled)
                log.Debug("Get Resource value... resourceKey=[{0}], culture=[{1}], AssemblyName=[{2}], ResourceName=[{3}]",
                          resourceKey, culture, AssemblyName, ResourceName);

            culture = culture.GetCulture();

            // 캐시 확인
            Hashtable resourceValues = null;

            if(_resourcesCache.TryGetValue(culture, out resourceValues)) {
                if(resourceValues.ContainsKey(resourceKey))
                    return resourceValues[resourceKey];
            }

            // DB에서 해당 정보 조회
            var result = Repository.GetResource(culture, resourceKey);

            // 캐시에 저장
            lock(_syncLock) {
                if(_resourcesCache.TryGetValue(culture, out resourceValues) == false) {
                    resourceValues = new Hashtable();
                    _resourcesCache.Add(culture, resourceValues);
                }

                // NOTE: MultiThread 상태에서 lock이 걸려 있어도, resourceValues에 기존 key가 있을 경우에는 넣지 않는다!!!
                //
                if(resourceValues.ContainsKey(resourceKey) == false)
                    resourceValues.Add(resourceKey, result);
            }

            return result;
        }