【问题标题】:SelectMany type arguments cannot be inferred from usageSelectMany 类型参数不能从用法中推断出来
【发布时间】:2016-02-05 19:14:00
【问题描述】:

我有一个控制器,上面有一些动作,其中一些可能有自定义属性。我想使用 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 上遇到错误 - 方法的类型参数...无法从用法中推断出来。

【问题讨论】:

  • 您是否尝试过使用 Select 而不是 SelectMany?每个类型都不是一个集合是吗?
  • myControllerList 是一个集合,对于每个控制器,可能有多个具有自定义属性的方法,所以如果这有意义的话,我需要为控制器中的每个方法创建一个项目? @ChrisWohlert
  • 我想这是有道理的,但是在您的示例代码中,您并没有尝试返回所有属性,而只是返回第一个属性。如果 Rui 的回答不是你想要的,我会很惊讶。如果是,您应该接受它作为答案。 :)

标签: c# linq


【解决方案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);
};

您可以只使用 .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();

【讨论】:

  • 我需要为每个控制器返回多个元素 - 选择不起作用,请参阅上述问题的更新
【解决方案2】:

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

SelectMany 替换为Select 就可以了。

【讨论】:

    【解决方案3】:

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

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

    只是一个建议(并且是空气编码的,所以可能有语法错误),但是如果您查询所有方法(selectmany),根据方法信息缓冲属性,然后检查填充位置,您只搜索属性一次:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-29
      • 2013-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多