我正在尝试编写一个接受任何IEnumerable<T>
作为参数的方法;并从代码中调用它,直到运行时才会知道T
。
我可以将它作为泛型方法编写,然后在我想使用时用反射调用它,但出于各种原因我决定使用类型动态。但是,当我从实体框架函数import(a System.Data.Objects.ObjectQuery<T>
)传入强类型集合输出并尝试访问Count()方法时,它引发了System.Data.Objects.ObjectQuery<T>
没有的效果的异常有一个Count()方法,但情况并非如此。
我通过将与对象的交互限制为foreach语句来解决这个问题,从而使编译器弄清楚如何枚举它,所以这不是问题。我更感兴趣的是理解为什么我不能这样做。我的猜测是,Count()是基类或接口上的方法,因此由于某种原因无法访问,或者编译器通常在编译期间将对Count()的调用转换为Count<T>
而不能在这种情况下这样做?帮助赞赏。
编辑:我觉得编译器可能没有将非通用Count()
转换为通用Count<T>
。当您在Count()
上调用IEnumerable<T>.Count()
时,实际上正在调用Count<T>()
,这只是编译器负责的语法糖。我认为它可能不会在运行时将Count()
转换为Count<T>()
。很高兴得到对此的确认,因为如果是这样,这对于使用类型动态的泛型来说是一个非常烦人的限制。
还编辑添加代码:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException未被用户代码处理HResult = -2146233088 Message ='System.Data.Objects.ObjectResult'不包含'Count'的定义 Source =匿名托管DynamicMethods程序集 堆栈跟踪: 在CallSite.Target(Closure,CallSite,Object) 在System.Dynamic.UpdateDelegates.UpdateAndExecute1 [T0,TRet](CallSite站点,T0 arg0) at [snip]中的MyNamespace.HtmlHelpers.RenderTable(Object list,String id,String cssClass)
抛出异常的代码示例:
public static MvcHtmlString RenderTable(dynamic list, string id, string cssClass)
{
int x = list.Count();
........
........
}
答案 0 :(得分:0)
当list.Count()
为list
时,dynamic
给出运行时错误的原因是Count
是一种扩展方法 - Enumerable.Count<T>
- 并且扩展方法只能在编译时被发现。 (有人纠正我,如果我错了 - 这是我的理解。)
在直接回答你的问题之前,先看看这个小玩具程序。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Example
{
class Program
{
static void Main(string[] args)
{
IEnumerable<int> a = Enumerable.Range(1, 3);
IEnumerable b = a;
IEnumerable<double> c = b.SelectTimesPi();
foreach (var x in c)
{
Console.WriteLine(x);
}
Console.ReadLine();
}
}
static class Extensions
{
public static IEnumerable<double> SelectTimesPi(this IEnumerable source)
{
return source
.Cast<dynamic>()
.Select(x => Math.PI * x)
.Cast<double>();
}
}
}
其输出如下。
3.14159265358979
6.28318530717959
9.42477796076938
SelectTimesPi
扩展方法采用任何IEnumerable<T>
,其中T
仅在运行时已知,然后将其元素作为dynamic
值进行操作。 source
可以是IEnumerable<byte>
,IEnumerable<short>
,IEnumerable<float>
等。
你可以使用非扩展方法做同样的事情,就像你问的那样。我只是用它作为例子,因为看起来你的目标是最终创建一个扩展方法。
诀窍是在Enumerable.Cast<dynamic>
上使用IEnumerable
。
回到原来的问题。您只需将RenderTable
方法设为list
而不是IEnumerable
,然后使用dynamic
。
Enumerable.Cast<dynamic>
现在对public static MvcHtmlString RenderTable(IEnumerable list, string id, string cssClass)
{
IEnumerable<dynamic> dynamicList = list.Cast<dynamic>();
int x = dynamicList.Count();
...
}
的调用是而不是动态调度,因此扩展方法可以正常工作。
总结:
Count
答案 1 :(得分:0)
这个小程序可以证明这个问题:
using System;
namespace SO24255725
{
public static class Extension
{
public static int Count(this Program a)
{
return 42;
}
}
public class Program
{
static void Main()
{
Program test = new Program();
PrintCount(test);
}
static void PrintCount(dynamic data)
{
Console.WriteLine(data.Count());
}
}
}
原因如下:
动态功能无法在运行时任意绑定到扩展名 方法,因为扩展方法功能被定义为作用域 仅限于使用编译单元的#。在运行时,使用&#39; 信息消失了,所以运行时绑定程序无法解析 扩展方法。这是设计......
您没有列出&#34;各种原因&#34;为什么你决定使用动态。可能你不应该。