2016-02-05 41 views
4

我有一个控制器,它有几个动作,其中一些可能有一个自定义属性。我想使用linq为控制器上的每个动作选择一些匿名类型的数据。SelectMany类型参数不能从使用推断

Controller1 
    Action1 
    [MyAttribute("Con1Action2)"] 
    Action2 
    [MyAttribute("Con1Action3")] 
    Action3 


    Controller2 
    Action1 
    [MyAttribute("Con2Action2)"] 
    Action2 
    [MyAttribute("Con2Action3")] 
    Action3 

我想下面返回:

var controllers= myControllerList 
.Where(type =>type.Namespace.StartsWith("X.") && 
    type.GetMethods().Any(m => m.GetCustomAttributes(typeof(MyAttribute)).Any())) 
.SelectMany(type => 
{ 
    var actionNames = type.GetMethods().Where(m => m.GetCustomAttributes(typeof(MyAttribute)).Any()).ToList(); 

    var actionName = (MyAttribute)actionNames[0].GetCustomAttribute(typeof(MyAttribute)); 
    return new 
    { 
     Namespace = GetPath(type.Namespace), 
     ActionName= actionName.Name, 
     Controller = type.Name.Remove(2); 
    }; 
}).ToList(); 

我在SelectMany-类型得到一个错误:

NameSpace = "someText", Controller = "Controller1", ActionName = "Con1Action2", 
NameSpace = "someText", Controller = "Controller1", ActionName = "Con1Action3", 
NameSpace = "someText", Controller = "Controller2", ActionName = "Con2Action2", 
NameSpace = "someText", Controller = "Controller2", ActionName = "Con2Action3" 

我为每个动作挣扎的SelectMany该方法的参数...不能从使用中推断出来。

+1

您是否尝试过使用Select而不是SelectMany?每种类型是不是一个集合呢? –

+0

myControllerList是一个集合,对于每个控制器,可能有多个具有custome属性的方法,所以如果这有意义的话,我需要一个控制器中每个方法的项目。 @ChrisWohlert –

+0

我想这是有道理的,但在你的示例代码中,你并没有试图返回所有的属性,只有第一个。如果瑞的回答不是你想要的,我很惊讶。如果是这样,你应该接受它作为答案。 :) –

回答

1

“SelectMany将序列的每个元素投影到IEnumerable中,并将结果序列展平成一个序列。” 来源:https://msdn.microsoft.com/en-us/library/system.linq.enumerable.selectmany(v=vs.100).aspx

你返回一个元素:

return new 
{ 
    Namespace = GetPath(type.Namespace), 
    ActionName= actionName.Name, 
    Controller = type.Name.Remove(2); 
}; 

你可以使用。选择

你会使用如的SelectMany你想从那个是一个属性扁平列表一个保藏中心,例如:

projects.SelectMany(p => p.Technologies).ToList()

假设一个项目有一个属性,是一个名为Technologies的集合,该查询将返回所有项目的所有技术。

在你的情况,因为你想要的每个控制器操作的列表,你必须返回的每个控制器动作信息的列表:

var controllers= myControllerList 
.Where(type =>type.Namespace.StartsWith("X.") && 
    type.GetMethods().Any(m => m.GetCustomAttributes(typeof(MyAttribute)).Any())) 
.SelectMany(type => 
{ 
    var actionNames = type.GetMethods().Where(m => m.GetCustomAttributes(typeof(MyAttribute)).Any()).ToList(); 

    return actionNames.Select(action => { 
     var actionName = (MyAttribute)action.GetCustomAttribute(typeof(MyAttribute)); 
     return new 
     { 
      Namespace = GetPath(type.Namespace), 
      ActionName= actionName.Name, 
      Controller = type.Name.Remove(2);  
     }); 
    });  
}).ToList(); 
+0

我需要为每个控制器返回多个元素 - 选择不起作用,请参阅上述问题的更新 –

0

我相信这个问题是SelectMany。它预计在IEnumerable<T>上执行您正在调用的类型,在这种情况下为Type。但Type不执行IEnumerable<T>。因此它会出错。

Select替换SelectMany,你会没事的。

0

如上所述,问题是单个对象返回new {}其中selectmany需要一个集合。

在您当前的设置中,您可以通过在selectmany中的操作(例如return actionNames.Select(a=> new {...)上返回一个select来做到这一点,以便返回包含每个单独属性的枚举,但在此设置中,属性将被多次查询。 (一次为检查,一次为执行)

只是一个建议(和航空编码,所以可能有语法错误),但如果你查询所有方法(selectmany),缓冲每个methodinfo属性,然后检查填充位置,您只搜索一次属性:

var controllers= myControllerList 
.Where(type =>type.Namespace.StartsWith("X.")) 
.SelectMany(type => type.GetMethods()) 
.Select(m => new { 
    Type = m.DeclaringType, 
    Att = m.GetCustomAttribute(typeof(MyAttribute)) as MyAttribute 
}) 
.Where(t=>t.Att!=null) 
.Select(t=> new 
    { 
     Namespace = GetPath(t.Type.Namespace), 
     ActionName= t.Att.Name, 
     Controller = t.Type.Name.Remove(2); 
    } 
).ToList(); 
相关问题