input,ValueProvider 回傳字串陣列,ConvertTo(int[]) 自動轉型。prefix[0]、prefix[1]...,逐一繫結元素。var data = new NameValueCollection();
data.Add("foo", "123");
data.Add("foo", "456");
data.Add("foo", "789");
var provider = new NameValueCollectionValueProvider(data, CultureInfo.InvariantCulture);
var result = provider.GetValue("foo");
result.RawValue; // string[] { "123", "456", "789" }
result.ConvertTo(typeof(int[])); // int[] { 123, 456, 789 }
result.ConvertTo(typeof(int)); // 123 (僅取第一個)
public class DefaultModelBinder
{
public object BindModel(Type parameterType, string prefix)
{
if (!ValueProvider.ContainsPrefix(prefix)) return null;
var metadata = ModelMetadataProviders.Current.GetMetadataForType(() => null, parameterType);
if (!metadata.IsComplexType) return ValueProvider.GetValue(prefix).ConvertTo(parameterType);
if (parameterType.IsArray) return BindArrayModel(parameterType, prefix);
// ... 複雜型別邏輯
}
private object BindArrayModel(Type parameterType, string prefix)
{
var list = new List<object>();
// 1. 同名多值直接轉換
if (ValueProvider.ContainsPrefix(prefix))
{
var enumerable = ValueProvider.GetValue(prefix).ConvertTo(parameterType) as IEnumerable;
if (enumerable != null) foreach (var v in enumerable) list.Add(v);
}
// 2. 索引式繫結(陣列通常不支援索引式?實際上 MVC 支援)
// 這裡簡化:若上述已取得值則不再索引式繫結
var array = Array.CreateInstance(parameterType.GetElementType(), list.Count);
list.CopyTo(array, 0);
return array;
}
}
<input name="Foo" type="text" /> <!-- 三個同名 -->
<input name="Foo" type="text" />
<input name="Foo" type="text" />
<input name="Bar" type="file" /> <!-- 三個檔案 -->
<input name="Bar" type="file" />
<input name="Bar" type="file" />
Action:
public void ActionMethod(string[] foo, HttpPostedFileBase[] bar) { ... }
foo 繫結三個字串,bar 繫結三個上傳檔案。
繼承 DictionaryValueProvider<HttpPostedFileBase[]>,鍵為 input name,值為同名檔案陣列,完美支援多檔上傳繫結。
陣列繫結核心在於 NameValueCollectionValueProvider 的多值轉換特性。模擬繫結器只需處理「同名多值直接轉換」即涵蓋 90% 情境,索引式繫結在集合/字典更常見。理解此機制可正確設計表單欄位名稱對應 Action 參數。