博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Asp.net MVC DefaultModelBinder分析
阅读量:5113 次
发布时间:2019-06-13

本文共 33495 字,大约阅读时间需要 111 分钟。

今天看见一同事写了一段代码很是奇怪,大致结构如下:

 public ActionResult Demo(string name, dynamic obj)

        {
            if (obj != null)
            {
                return Content("obj is not null");
            }
            return Content("obj is  null");
        }

在调用action时obj参数不传如@{Html.RenderAction("Demo",new {name="majiang"});}

可是在实际运行中obj永远不等于null。这是为什么了? 其实一切答案都在DefaultModelBinder

首先看看BindModel方法

public virtual object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {            if (bindingContext == null) {                throw new ArgumentNullException("bindingContext");            }            bool performedFallback = false;            if (!String.IsNullOrEmpty(bindingContext.ModelName) && !bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName)) {                // We couldn't find any entry that began with the prefix. If this is the top-level element, fall back                // to the empty prefix.                if (bindingContext.FallbackToEmptyPrefix) {                    bindingContext = new ModelBindingContext() {                        ModelMetadata = bindingContext.ModelMetadata,                        ModelState = bindingContext.ModelState,                        PropertyFilter = bindingContext.PropertyFilter,                        ValueProvider = bindingContext.ValueProvider                    };                    performedFallback = true;                }                else {                    return null;                }            }            // Simple model = int, string, etc.; determined by calling TypeConverter.CanConvertFrom(typeof(string))            // or by seeing if a value in the request exactly matches the name of the model we're binding.            // Complex type = everything else.            if (!performedFallback) {                bool performRequestValidation = ShouldPerformRequestValidation(controllerContext, bindingContext);                ValueProviderResult vpResult = bindingContext.UnvalidatedValueProvider.GetValue(bindingContext.ModelName, skipValidation: !performRequestValidation);                if (vpResult != null) {                    return BindSimpleModel(controllerContext, bindingContext, vpResult);                }            }            if (!bindingContext.ModelMetadata.IsComplexType) {                return null;            }            return BindComplexModel(controllerContext, bindingContext);        }

很显然object是复杂类型 应该关注方法BindComplexModel

 

internal object BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {            object model = bindingContext.Model;            Type modelType = bindingContext.ModelType;            // if we're being asked to create an array, create a list instead, then coerce to an array after the list is created            if (model == null && modelType.IsArray) {                Type elementType = modelType.GetElementType();                Type listType = typeof(List<>).MakeGenericType(elementType);                object collection = CreateModel(controllerContext, bindingContext, listType);                ModelBindingContext arrayBindingContext = new ModelBindingContext() {                    ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => collection, listType),                    ModelName = bindingContext.ModelName,                    ModelState = bindingContext.ModelState,                    PropertyFilter = bindingContext.PropertyFilter,                    ValueProvider = bindingContext.ValueProvider                };                IList list = (IList)UpdateCollection(controllerContext, arrayBindingContext, elementType);                if (list == null) {                    return null;                }                Array array = Array.CreateInstance(elementType, list.Count);                list.CopyTo(array, 0);                return array;            }            if (model == null) {                model = CreateModel(controllerContext, bindingContext, modelType);            }            // special-case IDictionary<,> and ICollection<>            Type dictionaryType = TypeHelpers.ExtractGenericInterface(modelType, typeof(IDictionary<,>));            if (dictionaryType != null) {                Type[] genericArguments = dictionaryType.GetGenericArguments();                Type keyType = genericArguments[0];                Type valueType = genericArguments[1];                ModelBindingContext dictionaryBindingContext = new ModelBindingContext() {                    ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, modelType),                    ModelName = bindingContext.ModelName,                    ModelState = bindingContext.ModelState,                    PropertyFilter = bindingContext.PropertyFilter,                    ValueProvider = bindingContext.ValueProvider                };                object dictionary = UpdateDictionary(controllerContext, dictionaryBindingContext, keyType, valueType);                return dictionary;            }            Type enumerableType = TypeHelpers.ExtractGenericInterface(modelType, typeof(IEnumerable<>));            if (enumerableType != null) {                Type elementType = enumerableType.GetGenericArguments()[0];                Type collectionType = typeof(ICollection<>).MakeGenericType(elementType);                if (collectionType.IsInstanceOfType(model)) {                    ModelBindingContext collectionBindingContext = new ModelBindingContext() {                        ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, modelType),                        ModelName = bindingContext.ModelName,                        ModelState = bindingContext.ModelState,                        PropertyFilter = bindingContext.PropertyFilter,                        ValueProvider = bindingContext.ValueProvider                    };                    object collection = UpdateCollection(controllerContext, collectionBindingContext, elementType);                    return collection;                }            }            // otherwise, just update the properties on the complex type            BindComplexElementalModel(controllerContext, bindingContext, model);            return model;        }

 

在它里面有关键的一句

if (model == null) {
                model = CreateModel(controllerContext, bindingContext, modelType);
            }

 

protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)        {            Type typeToCreate = modelType;            // we can understand some collection interfaces, e.g. IList<>, IDictionary<,>            if (modelType.IsGenericType)            {                Type genericTypeDefinition = modelType.GetGenericTypeDefinition();                if (genericTypeDefinition == typeof(IDictionary<,>))                {                    typeToCreate = typeof(Dictionary<,>).MakeGenericType(modelType.GetGenericArguments());                }                else if (genericTypeDefinition == typeof(IEnumerable<>) || genericTypeDefinition == typeof(ICollection<>) || genericTypeDefinition == typeof(IList<>))                {                    typeToCreate = typeof(List<>).MakeGenericType(modelType.GetGenericArguments());                }            }            // fallback to the type's default constructor            return Activator.CreateInstance(typeToCreate);        }

 

很明显 在绑定的时候发现复杂类型实例为null,这时DefaultModelBinder会创建一个默认实例。这就是为什么action参数为object的时候,再绑定后都不为null。然而string类型的数据他们走的是BindSimpleModel。

为了便于大家调试代码,证实以上结论,大家可以创建一个类继承与DefaultModelBinder,如CustBinder

然后再Application_Start() 中添加一句   ModelBinders.Binders.DefaultBinder = new CustBinder();

CustBinder代码:

public class CustBinder : DefaultModelBinder    {        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)        {            //return base.BindModel(controllerContext, bindingContext);            if (bindingContext == null)            {                throw new ArgumentNullException("bindingContext");            }            bool performedFallback = false;            if (!String.IsNullOrEmpty(bindingContext.ModelName) && !bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName))            {                // We couldn't find any entry that began with the prefix. If this is the top-level element, fall back                // to the empty prefix.                if (bindingContext.FallbackToEmptyPrefix)                {                    bindingContext = new ModelBindingContext()                    {                        ModelMetadata = bindingContext.ModelMetadata,                        ModelState = bindingContext.ModelState,                        PropertyFilter = bindingContext.PropertyFilter,                        ValueProvider = bindingContext.ValueProvider                    };                    performedFallback = true;                }                else                {                    return null;                }            }            // Simple model = int, string, etc.; determined by calling TypeConverter.CanConvertFrom(typeof(string))            // or by seeing if a value in the request exactly matches the name of the model we're binding.            // Complex type = everything else.            if (!performedFallback)            {                bool performRequestValidation = ShouldPerformRequestValidation(controllerContext, bindingContext);                //ValueProviderResult vpResult = bindingContext.UnvalidatedValueProvider.GetValue(bindingContext.ModelName, skipValidation: !performRequestValidation);                ValueProviderResult vpResult = (bindingContext.ValueProvider as IUnvalidatedValueProvider).GetValue(bindingContext.ModelName, skipValidation: !performRequestValidation);                if (vpResult != null)                {                    return BindSimpleModel(controllerContext, bindingContext, vpResult);                }            }            if (!bindingContext.ModelMetadata.IsComplexType)            {                return null;            }            return BindComplexModel(controllerContext, bindingContext);        }        protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)        {            Type typeToCreate = modelType;            // we can understand some collection interfaces, e.g. IList<>, IDictionary<,>            if (modelType.IsGenericType)            {                Type genericTypeDefinition = modelType.GetGenericTypeDefinition();                if (genericTypeDefinition == typeof(IDictionary<,>))                {                    typeToCreate = typeof(Dictionary<,>).MakeGenericType(modelType.GetGenericArguments());                }                else if (genericTypeDefinition == typeof(IEnumerable<>) || genericTypeDefinition == typeof(ICollection<>) || genericTypeDefinition == typeof(IList<>))                {                    typeToCreate = typeof(List<>).MakeGenericType(modelType.GetGenericArguments());                }            }            // fallback to the type's default constructor            return Activator.CreateInstance(typeToCreate);        }        internal object BindSimpleModel(ControllerContext controllerContext, ModelBindingContext bindingContext, ValueProviderResult valueProviderResult)        {            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);            // if the value provider returns an instance of the requested data type, we can just short-circuit            // the evaluation and return that instance            if (bindingContext.ModelType.IsInstanceOfType(valueProviderResult.RawValue))            {                return valueProviderResult.RawValue;            }            // since a string is an IEnumerable
, we want it to skip the two checks immediately following if (bindingContext.ModelType != typeof(string)) { // conversion results in 3 cases, as below if (bindingContext.ModelType.IsArray) { // case 1: user asked for an array // ValueProviderResult.ConvertTo() understands array types, so pass in the array type directly object modelArray = ConvertProviderResult(bindingContext.ModelState, bindingContext.ModelName, valueProviderResult, bindingContext.ModelType); return modelArray; } Type enumerableType = TypeHelpers.ExtractGenericInterface(bindingContext.ModelType, typeof(IEnumerable<>)); if (enumerableType != null) { // case 2: user asked for a collection rather than an array // need to call ConvertTo() on the array type, then copy the array to the collection object modelCollection = CreateModel(controllerContext, bindingContext, bindingContext.ModelType); Type elementType = enumerableType.GetGenericArguments()[0]; Type arrayType = elementType.MakeArrayType(); object modelArray = ConvertProviderResult(bindingContext.ModelState, bindingContext.ModelName, valueProviderResult, arrayType); Type collectionType = typeof(ICollection<>).MakeGenericType(elementType); if (collectionType.IsInstanceOfType(modelCollection)) { CollectionHelpers.ReplaceCollection(elementType, modelCollection, modelArray); } return modelCollection; } } // case 3: user asked for an individual element object model = ConvertProviderResult(bindingContext.ModelState, bindingContext.ModelName, valueProviderResult, bindingContext.ModelType); return model; } internal object BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { object model = bindingContext.Model; Type modelType = bindingContext.ModelType; // if we're being asked to create an array, create a list instead, then coerce to an array after the list is created if (model == null && modelType.IsArray) { Type elementType = modelType.GetElementType(); Type listType = typeof(List<>).MakeGenericType(elementType); object collection = CreateModel(controllerContext, bindingContext, listType); ModelBindingContext arrayBindingContext = new ModelBindingContext() { ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => collection, listType), ModelName = bindingContext.ModelName, ModelState = bindingContext.ModelState, PropertyFilter = bindingContext.PropertyFilter, ValueProvider = bindingContext.ValueProvider }; IList list = (IList)UpdateCollection(controllerContext, arrayBindingContext, elementType); if (list == null) { return null; } Array array = Array.CreateInstance(elementType, list.Count); list.CopyTo(array, 0); return array; } if (model == null) { model = CreateModel(controllerContext, bindingContext, modelType); } // special-case IDictionary<,> and ICollection<> Type dictionaryType = TypeHelpers.ExtractGenericInterface(modelType, typeof(IDictionary<,>)); if (dictionaryType != null) { Type[] genericArguments = dictionaryType.GetGenericArguments(); Type keyType = genericArguments[0]; Type valueType = genericArguments[1]; ModelBindingContext dictionaryBindingContext = new ModelBindingContext() { ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, modelType), ModelName = bindingContext.ModelName, ModelState = bindingContext.ModelState, PropertyFilter = bindingContext.PropertyFilter, ValueProvider = bindingContext.ValueProvider }; object dictionary = UpdateDictionary(controllerContext, dictionaryBindingContext, keyType, valueType); return dictionary; } Type enumerableType = TypeHelpers.ExtractGenericInterface(modelType, typeof(IEnumerable<>)); if (enumerableType != null) { Type elementType = enumerableType.GetGenericArguments()[0]; Type collectionType = typeof(ICollection<>).MakeGenericType(elementType); if (collectionType.IsInstanceOfType(model)) { ModelBindingContext collectionBindingContext = new ModelBindingContext() { ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, modelType), ModelName = bindingContext.ModelName, ModelState = bindingContext.ModelState, PropertyFilter = bindingContext.PropertyFilter, ValueProvider = bindingContext.ValueProvider }; object collection = UpdateCollection(controllerContext, collectionBindingContext, elementType); return collection; } } // otherwise, just update the properties on the complex type BindComplexElementalModel(controllerContext, bindingContext, model); return model; } internal void BindComplexElementalModel(ControllerContext controllerContext, ModelBindingContext bindingContext, object model) { // need to replace the property filter + model object and create an inner binding context ModelBindingContext newBindingContext = CreateComplexElementalModelBindingContext(controllerContext, bindingContext, model); // validation if (OnModelUpdating(controllerContext, newBindingContext)) { BindProperties(controllerContext, newBindingContext); OnModelUpdated(controllerContext, newBindingContext); } } internal ModelBindingContext CreateComplexElementalModelBindingContext(ControllerContext controllerContext, ModelBindingContext bindingContext, object model) { BindAttribute bindAttr = (BindAttribute)GetTypeDescriptor(controllerContext, bindingContext).GetAttributes()[typeof(BindAttribute)]; Predicate
newPropertyFilter = (bindAttr != null) ? propertyName => bindAttr.IsPropertyAllowed(propertyName) && bindingContext.PropertyFilter(propertyName) : bindingContext.PropertyFilter; ModelBindingContext newBindingContext = new ModelBindingContext() { ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, bindingContext.ModelType), ModelName = bindingContext.ModelName, ModelState = bindingContext.ModelState, PropertyFilter = newPropertyFilter, ValueProvider = bindingContext.ValueProvider }; return newBindingContext; } internal object UpdateCollection(ControllerContext controllerContext, ModelBindingContext bindingContext, Type elementType) { bool stopOnIndexNotFound; IEnumerable
indexes; GetIndexes(bindingContext, out stopOnIndexNotFound, out indexes); IModelBinder elementBinder = Binders.GetBinder(elementType); // build up a list of items from the request List
modelList = new List(); foreach (string currentIndex in indexes) { string subIndexKey = CreateSubIndexName(bindingContext.ModelName, currentIndex); if (!bindingContext.ValueProvider.ContainsPrefix(subIndexKey)) { if (stopOnIndexNotFound) { // we ran out of elements to pull break; } else { continue; } } ModelBindingContext innerContext = new ModelBindingContext() { ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, elementType), ModelName = subIndexKey, ModelState = bindingContext.ModelState, PropertyFilter = bindingContext.PropertyFilter, ValueProvider = bindingContext.ValueProvider }; object thisElement = elementBinder.BindModel(controllerContext, innerContext); // we need to merge model errors up AddValueRequiredMessageToModelState(controllerContext, bindingContext.ModelState, subIndexKey, elementType, thisElement); modelList.Add(thisElement); } // if there weren't any elements at all in the request, just return if (modelList.Count == 0) { return null; } // replace the original collection object collection = bindingContext.Model; CollectionHelpers.ReplaceCollection(elementType, collection, modelList); return collection; } internal object UpdateDictionary(ControllerContext controllerContext, ModelBindingContext bindingContext, Type keyType, Type valueType) { bool stopOnIndexNotFound; IEnumerable
indexes; GetIndexes(bindingContext, out stopOnIndexNotFound, out indexes); IModelBinder keyBinder = Binders.GetBinder(keyType); IModelBinder valueBinder = Binders.GetBinder(valueType); // build up a list of items from the request List
> modelList = new List
>(); foreach (string currentIndex in indexes) { string subIndexKey = CreateSubIndexName(bindingContext.ModelName, currentIndex); string keyFieldKey = CreateSubPropertyName(subIndexKey, "key"); string valueFieldKey = CreateSubPropertyName(subIndexKey, "value"); if (!(bindingContext.ValueProvider.ContainsPrefix(keyFieldKey) && bindingContext.ValueProvider.ContainsPrefix(valueFieldKey))) { if (stopOnIndexNotFound) { // we ran out of elements to pull break; } else { continue; } } // bind the key ModelBindingContext keyBindingContext = new ModelBindingContext() { ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, keyType), ModelName = keyFieldKey, ModelState = bindingContext.ModelState, ValueProvider = bindingContext.ValueProvider }; object thisKey = keyBinder.BindModel(controllerContext, keyBindingContext); // we need to merge model errors up AddValueRequiredMessageToModelState(controllerContext, bindingContext.ModelState, keyFieldKey, keyType, thisKey); if (!keyType.IsInstanceOfType(thisKey)) { // we can't add an invalid key, so just move on continue; } // bind the value ModelBindingContext valueBindingContext = new ModelBindingContext() { ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, valueType), ModelName = valueFieldKey, ModelState = bindingContext.ModelState, PropertyFilter = bindingContext.PropertyFilter, ValueProvider = bindingContext.ValueProvider }; object thisValue = valueBinder.BindModel(controllerContext, valueBindingContext); // we need to merge model errors up AddValueRequiredMessageToModelState(controllerContext, bindingContext.ModelState, valueFieldKey, valueType, thisValue); KeyValuePair
kvp = new KeyValuePair
(thisKey, thisValue); modelList.Add(kvp); } // if there weren't any elements at all in the request, just return if (modelList.Count == 0) { return null; } // replace the original collection object dictionary = bindingContext.Model; CollectionHelpers.ReplaceDictionary(keyType, valueType, dictionary, modelList); return dictionary; } private static bool ShouldPerformRequestValidation(ControllerContext controllerContext, ModelBindingContext bindingContext) { if (controllerContext == null || controllerContext.Controller == null || bindingContext == null || bindingContext.ModelMetadata == null) { // To make unit testing easier, if the caller hasn't specified enough contextual information we just default // to always pulling the data from a collection that goes through request validation. return true; } // We should perform request validation only if both the controller and the model ask for it. This is the // default behavior for both. If either the controller (via [ValidateInput(false)]) or the model (via [AllowHtml]) // opts out, we don't validate. return (controllerContext.Controller.ValidateRequest && bindingContext.ModelMetadata.RequestValidationEnabled); } private void BindProperties(ControllerContext controllerContext, ModelBindingContext bindingContext) { IEnumerable
properties = GetFilteredModelProperties(controllerContext, bindingContext); foreach (PropertyDescriptor property in properties) { BindProperty(controllerContext, bindingContext, property); } } private static void GetIndexes(ModelBindingContext bindingContext, out bool stopOnIndexNotFound, out IEnumerable
indexes) { string indexKey = CreateSubPropertyName(bindingContext.ModelName, "index"); ValueProviderResult vpResult = bindingContext.ValueProvider.GetValue(indexKey); if (vpResult != null) { string[] indexesArray = vpResult.ConvertTo(typeof(string[])) as string[]; if (indexesArray != null) { stopOnIndexNotFound = false; indexes = indexesArray; return; } } // just use a simple zero-based system stopOnIndexNotFound = true; indexes = GetZeroBasedIndexes(); } private static IEnumerable
GetZeroBasedIndexes() { for (int i = 0; ; i++) { yield return i.ToString(CultureInfo.InvariantCulture); } } private static void AddValueRequiredMessageToModelState(ControllerContext controllerContext, ModelStateDictionary modelState, string modelStateKey, Type elementType, object value) { if (value == null && !TypeHelpers.TypeAllowsNullValue(elementType) && modelState.IsValidField(modelStateKey)) { modelState.AddModelError(modelStateKey, GetValueRequiredResource(controllerContext)); } } private static string GetValueRequiredResource(ControllerContext controllerContext) { return "PropertyValueRequired"; } private static object ConvertProviderResult(ModelStateDictionary modelState, string modelStateKey, ValueProviderResult valueProviderResult, Type destinationType) { try { object convertedValue = valueProviderResult.ConvertTo(destinationType); return convertedValue; } catch (Exception ex) { modelState.AddModelError(modelStateKey, ex); return null; } } private static class CollectionHelpers { private static readonly MethodInfo _replaceCollectionMethod = typeof(CollectionHelpers).GetMethod("ReplaceCollectionImpl", BindingFlags.Static | BindingFlags.NonPublic); private static readonly MethodInfo _replaceDictionaryMethod = typeof(CollectionHelpers).GetMethod("ReplaceDictionaryImpl", BindingFlags.Static | BindingFlags.NonPublic); [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static void ReplaceCollection(Type collectionType, object collection, object newContents) { MethodInfo targetMethod = _replaceCollectionMethod.MakeGenericMethod(collectionType); targetMethod.Invoke(null, new object[] { collection, newContents }); } private static void ReplaceCollectionImpl
(ICollection
collection, IEnumerable newContents) { collection.Clear(); if (newContents != null) { foreach (object item in newContents) { // if the item was not a T, some conversion failed. the error message will be propagated, // but in the meanwhile we need to make a placeholder element in the array. T castItem = (item is T) ? (T)item : default(T); collection.Add(castItem); } } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static void ReplaceDictionary(Type keyType, Type valueType, object dictionary, object newContents) { MethodInfo targetMethod = _replaceDictionaryMethod.MakeGenericMethod(keyType, valueType); targetMethod.Invoke(null, new object[] { dictionary, newContents }); } private static void ReplaceDictionaryImpl
(IDictionary
dictionary, IEnumerable
> newContents) { dictionary.Clear(); foreach (KeyValuePair
item in newContents) { // if the item was not a T, some conversion failed. the error message will be propagated, // but in the meanwhile we need to make a placeholder element in the dictionary. TKey castKey = (TKey)item.Key; // this cast shouldn't fail TValue castValue = (item.Value is TValue) ? (TValue)item.Value : default(TValue); dictionary[castKey] = castValue; } } } } internal delegate bool TryGetValueDelegate(object dictionary, string key, out object value); internal static class TypeHelpers { private static readonly Dictionary
_tryGetValueDelegateCache = new Dictionary
(); private static readonly ReaderWriterLockSlim _tryGetValueDelegateCacheLock = new ReaderWriterLockSlim(); private static readonly MethodInfo _strongTryGetValueImplInfo = typeof(TypeHelpers).GetMethod("StrongTryGetValueImpl", BindingFlags.NonPublic | BindingFlags.Static); public static readonly Assembly MsCorLibAssembly = typeof(string).Assembly; public static readonly Assembly MvcAssembly = typeof(Controller).Assembly; public static readonly Assembly SystemWebAssembly = typeof(HttpContext).Assembly; // method is used primarily for lighting up new .NET Framework features even if MVC targets the previous version // thisParameter is the 'this' parameter if target method is instance method, should be null for static method public static TDelegate CreateDelegate
(Assembly assembly, string typeName, string methodName, object thisParameter) where TDelegate : class { // ensure target type exists Type targetType = assembly.GetType(typeName, false /* throwOnError */); if (targetType == null) { return null; } return CreateDelegate
(targetType, methodName, thisParameter); } public static TDelegate CreateDelegate
(Type targetType, string methodName, object thisParameter) where TDelegate : class { // ensure target method exists ParameterInfo[] delegateParameters = typeof(TDelegate).GetMethod("Invoke").GetParameters(); Type[] argumentTypes = Array.ConvertAll(delegateParameters, pInfo => pInfo.ParameterType); MethodInfo targetMethod = targetType.GetMethod(methodName, argumentTypes); if (targetMethod == null) { return null; } TDelegate d = Delegate.CreateDelegate(typeof(TDelegate), thisParameter, targetMethod, false /* throwOnBindFailure */) as TDelegate; return d; } public static TryGetValueDelegate CreateTryGetValueDelegate(Type targetType) { TryGetValueDelegate result; _tryGetValueDelegateCacheLock.EnterReadLock(); try { if (_tryGetValueDelegateCache.TryGetValue(targetType, out result)) { return result; } } finally { _tryGetValueDelegateCacheLock.ExitReadLock(); } Type dictionaryType = ExtractGenericInterface(targetType, typeof(IDictionary<,>)); // just wrap a call to the underlying IDictionary
.TryGetValue() where string can be cast to TKey if (dictionaryType != null) { Type[] typeArguments = dictionaryType.GetGenericArguments(); Type keyType = typeArguments[0]; Type returnType = typeArguments[1]; if (keyType.IsAssignableFrom(typeof(string))) { MethodInfo strongImplInfo = _strongTryGetValueImplInfo.MakeGenericMethod(keyType, returnType); result = (TryGetValueDelegate)Delegate.CreateDelegate(typeof(TryGetValueDelegate), strongImplInfo); } } // wrap a call to the underlying IDictionary.Item() if (result == null && typeof(IDictionary).IsAssignableFrom(targetType)) { result = TryGetValueFromNonGenericDictionary; } _tryGetValueDelegateCacheLock.EnterWriteLock(); try { _tryGetValueDelegateCache[targetType] = result; } finally { _tryGetValueDelegateCacheLock.ExitWriteLock(); } return result; } public static Type ExtractGenericInterface(Type queryType, Type interfaceType) { Func
matchesInterface = t => t.IsGenericType && t.GetGenericTypeDefinition() == interfaceType; return (matchesInterface(queryType)) ? queryType : queryType.GetInterfaces().FirstOrDefault(matchesInterface); } public static object GetDefaultValue(Type type) { return (TypeAllowsNullValue(type)) ? null : Activator.CreateInstance(type); } public static bool IsCompatibleObject
(object value) { return (value is T || (value == null && TypeAllowsNullValue(typeof(T)))); } public static bool IsNullableValueType(Type type) { return Nullable.GetUnderlyingType(type) != null; } private static bool StrongTryGetValueImpl
(object dictionary, string key, out object value) { IDictionary
strongDict = (IDictionary
)dictionary; TValue strongValue; bool retVal = strongDict.TryGetValue((TKey)(object)key, out strongValue); value = strongValue; return retVal; } private static bool TryGetValueFromNonGenericDictionary(object dictionary, string key, out object value) { IDictionary weakDict = (IDictionary)dictionary; bool containsKey = weakDict.Contains(key); value = (containsKey) ? weakDict[key] : null; return containsKey; } public static bool TypeAllowsNullValue(Type type) { return (!type.IsValueType || IsNullableValueType(type)); } }

 

 

 

转载于:https://www.cnblogs.com/majiang/archive/2012/08/30/2663421.html

你可能感兴趣的文章
洛谷 1449——后缀表达式(线性数据结构)
查看>>
Data truncation: Out of range value for column 'Quality' at row 1
查看>>
Dirichlet分布深入理解
查看>>
(转)Android之发送短信的两种方式
查看>>
字符串处理
查看>>
HtmlUnitDriver 网页内容动态抓取
查看>>
ad logon hour
查看>>
获得进程可执行文件的路径: GetModuleFileNameEx, GetProcessImageFileName, QueryFullProcessImageName...
查看>>
证件照(1寸2寸)拍摄处理知识汇总
查看>>
罗马数字与阿拉伯数字转换
查看>>
Eclipse 反编译之 JadClipse
查看>>
Python入门-函数
查看>>
[HDU5727]Necklace(二分图最大匹配,枚举)
查看>>
距离公式汇总以及Python实现
查看>>
设计模式之装饰者模式
查看>>
一道不知道哪里来的容斥题
查看>>
Blender Python UV 学习
查看>>
window添加右键菜单
查看>>
入手腾龙SP AF90mm MACRO
查看>>
Window7上搭建symfony开发环境(PEAR)
查看>>