程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> ASP.NET >> 關於ASP.NET >> 通過實例模擬ASP.NET MVC的Model綁定的機制:集合+字典

通過實例模擬ASP.NET MVC的Model綁定的機制:集合+字典

編輯:關於ASP.NET

在本系列的前面兩篇文章(《簡單類型+復雜類型》、《數組》)我們通過創建的實例程序模擬了ASP.NET MVC默認使用的DefaultModelBinder對簡單類型、復雜類型以及數組對象的Model綁定。現在我們按照相同的方式來分析基於集合和字典類型的Model綁定是如何實現的。[源代碼從這裡下載]

一、集合

這裡的集合指的是除數組和字典之外的所有實現IEnumerable<T>接口的類型。和基於數組的Model綁定類似,ValueProvider可以將多個同名的數據項作為集合的元素,基於索引(基零整數和字符串)的數據項命名方式同樣適用。我們對自定義的DefaultModelBinder作了如下的完善使之支持集合類型的Model綁定。

   1: public class DefaultModelBinder
2: {
3: //其他成員
4: public object BindModel(Type parameterType, string prefix)
5: {
6: if (!this.ValueProvider.ContainsPrefix(prefix))
7: {
8: return null;
9: }
10: ModelMetadata modelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => null, parameterType);
11: if (!modelMetadata.IsComplexType)
12: {
13: return this.ValueProvider.GetValue(prefix).ConvertTo(parameterType);
14: }
15: if (parameterType.IsArray)
16: {
17: return BindArrayModel(parameterType, prefix);
18: }
19: object model = CreateModel(parameterType);
20: Type enumerableType = ExtractGenericInterface(parameterType, typeof(IEnumerable<>));
21: if (null != enumerableType)
22: {
23: return BindCollectionModel(prefix, model, enumerableType);
24: }
25: foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(parameterType))
26: {
27: string key = prefix == "" ? property.Name : prefix + "." + property.Name;
28: property.SetValue(model, BindModel(property.PropertyType, key));
29: }
30: return model;
31: }
32:
33: private object BindCollectionModel(string prefix, object model, Type enumerableType)
34: {
35: List<object> list = new List<object>();
36: bool numericIndex;
37: IEnumerable<string> indexes = GetIndexes(prefix, out numericIndex);
38: Type elementType = enumerableType.GetGenericArguments()[0];
39:
40: if (!string.IsNullOrEmpty(prefix) && this.ValueProvider.ContainsPrefix(prefix))
41: {
42: IEnumerable enumerable = this.ValueProvider.GetValue(prefix).ConvertTo(enumerableType) as IEnumerable;
43: if (null != enumerable)
44: {
45: foreach (var value in enumerable)
46: {
47: list.Add(value);
48: }
49: }
50: }
51: foreach (var index in indexes)
52: {
53: string indexPrefix = prefix + "[" + index + "]";
54: if (!this.ValueProvider.ContainsPrefix(indexPrefix) && numericIndex)
55: {
56: break;
57: }
58: list.Add(BindModel(elementType, indexPrefix));
59: }
60: if (list.Count == 0)
61: {
62: return null;
63: }
64: ReplaceHelper.ReplaceCollection(elementType, model, list);
65: return model;
66: }
67:
68: private Type ExtractGenericInterface(Type queryType, Type interfaceType)
69: {
70: Func<Type, bool> predicate = t => t.IsGenericType && (t.GetGenericTypeDefinition() == interfaceType);
71: if (!predicate(queryType))
72: {
73: return queryType.GetInterfaces().FirstOrDefault<Type>(predicate);
74: }
75: return queryType;
76: }
77: }

如上面的代碼片斷所示,在BindModel方法中我們通過調用ExtractGenericInterface判斷目標類型是否實現了IEnumerable<T>接口,如果實現了該接口則提取泛型元素類型。針對集合的Model綁定實現在方法BindCollectionModel中,我們按照數組綁定的方式得的針對目標集合對象的所有元素對象,並將其添加到一個List<object>對象中,然後調用ReplaceHelper 的靜態方法ReplaceCollection將該列表中的元素拷貝到預先創建的Model對象中。定義在ReplaceHelper的靜態方法ReplaceCollection定義如下:

   1: internal static class ReplaceHelper
2: {
3: private static MethodInfo replaceCollectionMethod = typeof(ReplaceHelper).GetMethod("ReplaceCollectionImpl", BindingFlags.Static |BindingFlags.NonPublic);
4:
5: public static void ReplaceCollection(Type collectionType, object collection, object newContents)
6: {
7: replaceCollectionMethod.MakeGenericMethod(new Type[] { collectionType }).Invoke(null, new object[] { collection, newContents });
8: }
9: private static void ReplaceCollectionImpl<T>(ICollection<T> collection, IEnumerable newContents)
10: {
11: collection.Clear();
12: if (newContents != null)
13: {
14: foreach (object obj2 in newContents)
15: {
16: T item = (obj2 is T) ? ((T)obj2) : default(T);
17: collection.Add(item);
18: }
19: }
20: }
21: }

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved