IEnumerable <t>未知类型保留类信息</t>

时间:2015-03-09 08:37:47

标签: c# .net linq

我尝试编写一个带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.)

学术上仍然很好奇,如果在语言中有这种方法,但是:)

3 个答案:

答案 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();