2017-02-23 46 views
0

我想創建一個幫助器方法來爲MVC生成一個DropDown我已經涉足了表達式和反射,並且已經能夠獲取以下工作:方法的類型參數可以在方法調用中推斷爲1但不是2參數

public static DropDown GenerateDropDown<TSource, TProperty>(IEnumerable<TSource> source, 
      Expression<Func<TSource, TProperty>> text, 
      Expression<Func<TSource, object>> value, 
      string selectedValue = "", 
      string placeholder = "") where TSource : class 
     { 
... 
return new DropDown(...); 
} 

我可以比使用下面的代碼來生成一個下拉

DropDown.GenerateDropDown(routes, r => r.Name, r => r.Id, selectedValue, "Please Select One"); 

這種使用類型推斷聚集在列表(IEnumerable的)將是什麼樣的數據,並幫助我們確定應使用哪些屬性作爲文本和值,命名爲a nd Id。

注意上面的代碼有效!不過,我不喜歡使用object作爲Expression<Func<TSource, object>> value參數的第二個參數(它不能提供良好的智能感知)。但是,當我將其更改爲Expression<Func<TSource, TProperty>> value(就像它上面的參數),我得到的錯誤如下:

Error CS0411 The type arguments for method 'DropDown.GenerateDropDown<TSource, TProperty>(IEnumerable<TSource>, Expression<Func<TSource, TProperty>>, Expression<Func<TSource, TProperty>>, string, string)' cannot be inferred from the usage. Try specifying the type arguments explicitly.  

這究竟是爲什麼?怎麼可能有1個工作,但當添加/更改爲2時,它會失敗?

任何幫助非常感謝,提前致謝!

+2

「r.Name」和「r.Id」的數據類型是什麼? –

+0

@ScottChamberlain抱歉,我無法看到數據類型的重要性,但Name是字符串,Id是小數。 – Tyler

+0

'TProperty'不能引用2個不同的東西 - 你可以嘗試'GenerateDropDown '和'Expression >文本,表達式>值,但是它不清楚這是什麼點 –

回答

2

名稱是字符串,Id是小數。

TProperty的類型必須是整個方法的相同類型,您不能讓它表示一個位置中的一種數據類型和不同位置中的不同數據類型。如果你想擁有單獨的數據類型,你需要在聲明中使用3個泛型類型。

public static DropDown GenerateDropDown<TSource, TName, TValue>(IEnumerable<TSource> source, 
      Expression<Func<TSource, TName>> text, 
      Expression<Func<TSource, TValue>> value, 
      string selectedValue = "", 
      string placeholder = "") where TSource : class 
{ 
    ... 
    return new DropDown(...); 
} 

注意,如果text總是會返回一個字符串,你可以更改您的代碼

public static DropDown GenerateDropDown<TSource, TProperty>(IEnumerable<TSource> source, 
      Expression<Func<TSource, string>> text, 
      Expression<Func<TSource, TProperty>> value, 
      string selectedValue = "", 
      string placeholder = "") where TSource : class 
     { 
... 
return new DropDown(...); 
} 

+0

你是個天才! – Tyler

5

一個與此相關的評論:

哪些數據類型r.Name和r.Id?

您的迴應:

對不起,我看不到數據類型不管是什麼,但名稱是一個字符串ID是一個小數。

這是你沒有明白爲什麼它很重要,這解釋了爲什麼你被錯誤困惑。 (一般來說,你應該永遠不要相信各類不事當你的問題是關於類型推斷。類型是在類型推斷唯一重要的東西!)

隨着你的改變,你需要TProperty被推斷爲均爲stringdecimal。當面對這個問題時,C#不會說「字符串唯一的基本類型,而小數就是對象」,並推斷對象。相反,C#說「這個人認爲字符串和小數是同一個東西,因此程序可能是一個bug」。選擇對象在這裏是錯誤的。

在C#類型推斷的規則是(1)邊界被每種類型的參數來確定,然後(2)最好類型從類型界限選擇被拾取。 C#永遠不會「神奇起來」一種新的最佳類型。它永遠不會說,「嘿,你想要這個東西既是狗也是貓,因此它必須是動物」。它說「你希望我在狗和貓之間做出選擇,而且兩者都不會更好」。

現在,如果要求在狗與動物之間進行選擇,那麼顯然會更好:選擇更一般類型的動物。但是選擇的類型是,從始終選擇一組事物。

您可以在C#中看到這在其他許多地方:

var x = new[] { dog, cat }; 

這是一個錯誤,而不是動物的數組。但是

var x = new [] { dog, (Animal)cat }; 

是一組動物。

+0

很感謝!這是我對錶達式的誤解,我在看兩個表達式都返回給我一個'Type'(這正是我最終使用它們的),但顯然不止於此。 – Tyler

相關問題