无法从使用中推断出SelectMany类型参数

时间:2016-02-05 10:16:47

标签: c# linq

我有一个控制器,它有一些操作,其中一些可能有自定义属性。我想使用linq为控制器上的每个操作选择一些匿名类型的数据,例如

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


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

我希望返回以下内容:

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:

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上遇到错误 - 方法的类型参数...无法从用法中推断出来。

3 个答案:

答案 0 :(得分:2)

“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);
};

您可以使用.Select

如果你想从一个收集的属性中获取一个扁平列表,你可以使用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();

答案 1 :(得分:0)

我认为问题是SelectMany。它希望在IEnumerable<T>上实现您正在调用的类型,在本例中为Type。但Type未实现IEnumerable<T>。因此它会出错。

SelectMany替换为Select,你会没事的。

答案 2 :(得分:0)

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

在您当前的设置中,您可以通过返回selectmany中的操作选择(例如return actionNames.Select(a=> new {...)来执行此操作,以便返回包含每个单独属性的枚举,但在此设置中,属性将是多次查询。 (一次用于检查,一次用于实施)

只是一个建议(和空气编码,所以可能有语法错误),但如果你查询所有方法(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();