我尝试编写一个带IEnumerable<anything>
的属性过滤器并调用skip并接受它。
在OnActionExecuted中,我得到一个可以强制转换为IEnumerabe<object>
并调用skip并接受(完美)的对象,效果很好。
问题是跳过并且看起来很好,我被投射为IEnumerable<object>
所以我将返回IEnumerable<object>
完全消除类型信息的内容。
在大多数情况下这很好,但是我想使用多个属性并让它们检查类型信息以获取对象名称,第二个动作过滤器中的类型信息已成为对象。
无论如何基本上都有
var list = new List<string>{"a","b","c"};
var objectlist = list as IEnumerable<object>;
var newenumerable = objectlist.Take(10);
newenumerableastype = newenumerable as IEnumerable<string>
Assert.IsNotNull(newenumerableastype); //Currently this will be null as newenuerable is IEnumerable<object>
似乎没有强制从变量中输入IEnumerable的任何工具(我可以在LINQ查询之前得到这个,但是没有能够转换/转换它......它毫无意义)。
编辑:
我会尝试让它更清晰一点,我试图插入WebAPI2动作过滤器,这些基本上给了我一个真正的对象&#39;这是控制器上的返回类型。我可以使用反射来获得它是IEnumerable,甚至通过检查可枚举的类型来获取类型<T>
。
问题在于没有办法对待那个&#39;对象&#39;作为它的类型,但除了获取其类型信息之外,我并不关心实际类型T.
Take和Skip的C#扩展方法似乎创建了一种新的IEnumerable,它是前一个的子集,这就是我想要的,问题是它们在过程中删除了类型信息。
(IEnumerable<object> variable).Take(10) // returns an IEnumerable<object>
我非常喜欢我的方法1)不必预定义类型(向属性添加泛型可以工作,但语言不支持)或2)允许扩展方法返回IEnumerable<T>
基于IEnumerable<T>
构造的是什么,而不是它的构造。
更新:
所以在现实世界中制作&#39;事情工作,我发现我能够在ActionFilter的executionContext上使用不同的属性,这似乎有原始的类型信息(即使我搞乱了IEnumerable),所以过滤器链中的连续事物&#39;可以获取类型信息。
仍然是一个有趣的问题,如果我能以某种方式调用可枚举并保留类型信息,我会很好奇(除了奇怪的是如何在IEnumerable<T>
上定义,应该& #39;它真的存在于IEnumerable吗?那么Take需要知道对象类型是什么?它只需要返回它们的X.)
学术上仍然很好奇,如果在语言中有这种方法,但是:)
答案 0 :(得分:1)
似乎没有任何强制打字的工具 IEnumerable来自变量。
这是事实,因为IEnumerable的输入是一个编译时间的东西,变量的类型是运行时的东西。如果您知道IEnumerable中每个对象的所有类型都相同,那么您可以这样做:
List<string> list = new List<string>{"a","b","c"};
IEnumerable<object> objectlist = list as IEnumerable<object>;
IEnumerable<object> newenumerable = objectlist.Take(10);
Type listTypeOf = newenumerable.FirstOrDefault().GetType();
Type listType = typeof(List<>).MakeGenericType(listTypeOf);
dynamic dynamicList = Activator.CreateInstance(listType);
foreach (var item in newenumerable)
{
dynamicList.Add((dynamic) item);
}
IEnumerable<string> newenumerableastype = dynamicList as IEnumerable<string>;
Assert.IsNotNull(newenumerableastype);
在此示例中,这将起作用。在此示例中,dynamicList的类型是List<string>
。但是,如果对象的初始列表是混合类型,那么您将打开一些动态分辨率错误。例如,如果您将第一行代码更改为
List<object> list = new List<object>{"one", 2, 3.0};
然后你会得到一个RuntimeBinderException
,试图将一个整数添加到一个字符串列表中。这就是你最初的问题存在的原因。在不知道各个元素的所有类型的情况下,您无法安全地将IEnumerable<object>
投射到IEnumerable<string>
。
为了清楚起见,您可以确定示例中所有内容的类型,您只是在编译时不知道类型。正如您所知,Take懒惰地创建一个与源类型相同类型的新IEnumerable(这在编译时确定)。关于方差的C#规则尝试通过在编译时严格来减少运行时错误。您可以使用延迟评估并将特定类型的处理留到LINQ管道的末尾,并逐个类型地处理单个元素,但这将是运行时而不是编译时间类型。
答案 1 :(得分:0)
您可以使用Cast<>()
方法。
var newCollection = newenumerable.Cast<string>()
有关详细信息,请参阅msdn:https://msdn.microsoft.com/en-us/library/vstudio/bb341406%28v=vs.100%29.aspx
如果该对象集合中有不同的类型,您可以使用:
var newCollection = newenumerable.OfType<string>()
从通用集合中获取类型:
IEnumerable<object> myCollection = new List<string>();
var genericTypeArgument = myCollection.GetType().GetGenericArguments().FirstOrDefault();
答案 2 :(得分:-1)
使用此:
var newenumerable = objectlist.Cast<string>().AsEnumerable();