【问题标题】:How to specify .NET Anonymous object return type in Linq using Func<T,Q>?如何使用 Func<T,Q> 在 Linq 中指定 .NET 匿名对象返回类型?
【发布时间】:2009-02-27 20:14:50
【问题描述】:

如何为匿名对象指定 Func 签名?

new Func<DataSet, **IEnumerable<int>>**

我在 Func 声明中指定为 IEnumerable 的返回类型有问题

我从表达式中得到的错误是

无法将表达式类型“System.Collections.Generic.IEnumerable”转换为返回类型“System.Collections.Generic.IEnumerable”

如何在 func 中指定 IEnumerable

    public int GetCachedRootNodeId(IList<int> fromNodeIds, int forNodeId)
    {
        var result = forNodeId;

        const string spName = "spFetchAllParentNodeIDs";
        using (var ds = _df.ExecuteDatasetParamArray(_ConnectionString, spName, forNodeId))
        {
            if (DataAccessUtil.DataSetIsEmpty(ds)) return result;

            var orderByLevelDesc = new Func<DataSet, IEnumerable<int>>(resultSet =>
                from DataRow row in DataAccessUtil.GetFirstTableRows(resultSet) 
                orderby DataAccessUtil.GetInt32(row, "Level") descending 
                select new { ParentNodeId = DataAccessUtil.GetInt32(row, "ParentNodeID") });

            //// Get top-most parent's node ID first (higher the level, the more top-most the parent is)
            //var query = from DataRow row in DataAccessUtil.GetFirstTableRows(ds)
            //            orderby DataAccessUtil.GetInt32(row, "Level") descending
            //            select new { ParentNodeId = DataAccessUtil.GetInt32(row, "ParentNodeID") };
            //foreach (var nodeInfo in query)
            foreach (var nodeInfo in orderByLevelDesc(ds))
            {
                if (fromNodeIds.Contains(nodeInfo.ParentNodeId))
                    return nodeInfo.ParentNodeId;
            }
        }

        return result;
    }

顺便说一句,我可以使用注释代码“查询”并完成它。 但是想要更有表现力并在看到这个答案后尝试一些新的东西 Why doesn't C# have lexically nested functions?

编辑:最终结果

    public int GetCachedRootNodeId(IList<int> fromNodeIds, int forNodeId)
    {
        var result = forNodeId;

        const string spName = "spFetchAllParentNodeIDs";
        using (var ds = _df.ExecuteDatasetParamArray(_ConnectionString, spName, forNodeId))
        {
            if (DataAccessUtil.DataSetIsEmpty(ds)) return result;

            var orderParentNodeIDByLevelDesc = new Func<DataSet, IEnumerable<int>>(resultSet =>
                from DataRow row in DataAccessUtil.GetFirstTableRows(resultSet) 
                orderby DataAccessUtil.GetInt32(row, "Level") descending
                select DataAccessUtil.GetInt32(row, "ParentNodeID"));

            foreach (var parentNodeId in orderParentNodeIDByLevelDesc(ds))
            {
                if (fromNodeIds.Contains(parentNodeId))
                    return parentNodeId;
            }
        }

        return result;
    }

【问题讨论】:

    标签: c# linq anonymous-types


    【解决方案1】:

    这是一个想法——调用一个静态方法并让类型推断来做:

    public static Func<T, TResult> FuncOf(Func<T, TResult> func)
    {
        return func;
    }
    

    那就叫它吧:

    var orderByLevelDesc = FuncOf(resultSet =>
        from DataRow row in DataAccessUtil.GetFirstTableRows(resultSet) 
        orderby DataAccessUtil.GetInt32(row, "Level") descending 
        select new { ParentNodeId = DataAccessUtil.GetInt32(row, "ParentNodeID")
        });
    

    基本上你只需要“Func”部分告诉编译器它需要将 lambda 表达式转换为委托而不是表达式,以及委托的类型。它应该能够计算出给定 FuncOf 签名的类型。

    无论如何都值得一试。

    顺便说一句,我发现你的注释掉的版本更容易理解。为什么要引入一个额外的功能?或者您是否计划将其作为局部变量(这更有意义,但您不能使用var)?或者也许一个局部变量声明在外部循环而不是内部?

    【讨论】:

    • 这就像一个魅力。我只需要将 FuncOf 的签名更改为“public static Func FuncOf(Func func)”。并且在调用它时,“FuncOf(resultSet”到“FuncOf((DataSet resultSet”) 因为“GetFirstTableRows”方法需要一个 DataSet 并且它没有被推断出来。
    • 为什么要这么复杂?见我上面的回答。
    • @TheSoftwareJedi:我试图解决当前情况背后的问题,而不仅仅是解决这个特殊情况(我不得不承认,我没有详细研究)。两个有用的答案都以不同的方式:)
    • 当我必须返回多个属性时,您的答案很快就会派上用场。再次感谢您。
    【解决方案2】:

    在这种情况下,您真正​​想要的只是 int... 所以只需将您的选择更改为:

    select DataAccessUtil.GetInt32(row, "ParentNodeID"));
    

    并将你的 foreach 更改为:

    foreach (var nodeInfo in orderByLevelDesc(ds))
    {
        if (fromNodeIds.Contains(nodeInfo))
            return nodeInfo;
    }
    

    【讨论】:

    • 哈!这是我的初衷。谢谢。
    • 如果有人真的需要多属性匿名类,Jon Skeet 的回答非常棒。但在这种情况下,它只是一个 int!
    • 我会选择 Jon Skeet 的回答,因为我返回了你提到的多个属性。
    【解决方案3】:

    无法在声明中指定匿名类型。你必须为它创建一个命名类。

    Jon Skeet 在这个问题上有一个related blog entry

    【讨论】:

    • 我确实有一个博客条目,但我认为我们这次不必绝望:)
    • 其实我读的时候很喜欢。我只是想找个地方分享;)
    猜你喜欢
    • 2011-05-21
    • 1970-01-01
    • 2011-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多