2016-02-05 75 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();