2017-02-23 47 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

相关问题