LINQ加入和orderby问题

时间:2013-07-05 20:01:12

标签: c# linq c#-4.0

好吧,我几天来一直在反对这个问题,在学习LINQ之后我觉得我走在了正确的轨道上。但我有一个SQL大脑,有时很难转换为C#。

我有两个数组,一个按字母顺序排序,另一个按ID排序。我需要按字母顺序排序第二个数组。 ID是加入因子。 I.E. A.ID = P.ID。

这是我的数组和示例值;

private IGenericListItem[] _priceLevels = new IGenericListItem[0];
_priceLevels is in the form of {ID, Name}
{3, A}
{8, B}
{4, C}
{7, D}
{5, E}
{9, F}
{1, G}

编辑:更新了这个以显示_assignmentControls包含一个子数组。我没有为疯狂做这样的借口。它实际上包含_priceLevels的副本......

protected ArrayList _assignmentControls = new ArrayList();
_assignmentControls is in the form of {ID, LastPrice, NewPrice, _priceLevels[]}
{1, 1.00, 2.00, _priceLevels}
{2, 1.00, 2.00, _priceLevels}
{3, 1.00, 2.00, _priceLevels}
{4, 1.00, 2.00, _priceLevels}

部分问题在于我正在尝试比较/加入ArrayList和IGenericListItem。

In SQL I would do something like this;
SELECT A.* 
FROM _assignmentControls A JOIN _priceLevels P
    ON A.ID = P.ID
ORDER BY P.Name

这将返回一个按_priceLevels中的值排序的_assignmentControls表。

在C#LINQ中,我做到了这一点,但似乎无法做到正确;

        var sortedList =
            from a in _assignmentControls
            join p in _priceLevels on a equals p.ID
            orderby p.Name
            select _assignmentControls;

我在join和orderby下获得红色波浪形,p.Name中的p为红色。 并且A)它不起作用。 B)我不确定它会将sortedList作为按_priceLevels.Name排序的_assignmentControls的排序版本返回。

编辑:当我将鼠标悬停在“join”上时,我得到“方法的类型参数”IEnumerable System.Linq.Enumerable.Join(此Enumerable,IEnumerable,Func,Func ....'不能从查询中获取我现在在研究它。

感谢您的期待!

3 个答案:

答案 0 :(得分:6)

  

当我将鼠标悬停在“加入”上时,我得到“方法IEnumerable System.Linq.Enumerable.Join(this Enumerable,IEnumerable, Func,Func....的类型参数不能从查询中提取。

我可以解释这里发生了什么,以便你可以追踪它。

当你说

from firstitem in firstcollection
join seconditem in secondcollection on firstkey equals secondkey
select result

编译器将其转换为:

Enumerable.Join(
    firstcollection,
    secondcollection, 
    firstitem=>firstkey, 
    seconditem=>secondkey, 
    (firstitem, seconditem)=>result)

Enumerable.Join是一个通用方法,它有四个类型参数:第一个集合的元素类型,第二个集合的元素类型,键类型和结果类型。

如果您收到该错误,则根据您提供给编译器的信息,无法推断出这四件事中的一件。例如,也许:

  • 第一个集合的类型实际上不是序列。
  • 第二个集合的类型实际上不是一个序列。
  • 无法推断出结果的类型
  • 这两个键的类型不一致,没有唯一的最佳类型。

最后一点是最有可能的。例如,假设第一个键是int,第二个键是short。由于每个short都可以转换为intint将获胜,第二个密钥将自动转换为int。现在假设第一个键类型是Giraffe,第二个键类型是Tiger。两者都不比另一个好。 C#并没有说“哦,它们都是Animal,所以让我们选择它。”相反,它表示你没有提供足够的信息来确定你的意思;你应该将其中一个投射到Animal,然后它变得清晰。

有意义吗?

有一个半小时的视频我在2006年解释了这个功能 - 当我向编译器添加有问题的功能时,这又回来了 - 所以如果你想要更深入的解释,请查看它。

http://ericlippert.com/2006/11/17/a-face-made-for-email-part-three/

更新:我再次仔细阅读你的问题:

  

部分问题在于我正在尝试比较/加入ArrayListIGenericListItem

有问题。无法从ArrayList确定序列的类型。你不应该再使用ArrayList了。实际上,您不应该在2005年之后编写的任何代码中使用它。使用List<T>来获得一些合适的T。

答案 1 :(得分:3)

您的select条款错误,应该是这样的:

    var sortedList =
        from a in _assignmentControls
        join p in _priceLevels on a equals p.ID
        orderby p.Name
        select a;

另一个问题是_assignmentControls属于ArrayList类型,其类型为Object,因此编译器不知道a的实际类型,并且不能将其用作加入条件,因为ap.ID的类型不同。

您应该使用List<int>(假设p.ID类型为int)而不是ArrayList。另一种选择是明确指定a的类型:

    var sortedList =
        from int a in _assignmentControls
        join p in _priceLevels on a equals p.ID
        orderby p.Name
        select a;

答案 2 :(得分:2)

我认为你应该写:

var sortedList =
                from a in _assignmentControls
                join p in _priceLevels on a.ID equals p.ID
                orderby p.AnotherValue
                select a;

当您从_assignmentControls中写入时 - 您声明一个变量,该变量引用要执行的操作的sequance中的当前元素。当你调用select时 - 你正在从序列中投射元素。想象一下它就像传送带一样。

让我举一些关于转储数据的例子:

public class SomeCLass
        {
            public int ID { get; set; }
            public string Name { get; set; }
        }

        public class AnotherClass
        {
            public int ID { get; set; }
            public int Value { get; set; }
            public int AnotherValue { get; set; }
        }

public void TestMEthod()
        {
            List<SomeCLass> _assignmentControls = new List<SomeCLass>()
                {
                    new SomeCLass() { ID = 1, Name = "test"},
                    new SomeCLass() { ID = 2, Name = "another test"}
                };
            List<AnotherClass> _priceLevels = new List<AnotherClass>()
                {
                    new AnotherClass() {ID = 1, AnotherValue = 15, Value = 13},
                    new AnotherClass() {ID = 2, AnotherValue = 5, Value = 13}
                };


            var sortedList =
            //here you're declaring variable a that will be like caret when you going through _assignmentControls
            from a in _assignmentControls
            join p in _priceLevels on a.ID equals p.ID
            orderby p.AnotherValue
            select a;


            foreach (var someCLass in sortedList)
            {
                Console.WriteLine(someCLass.Name);
            }
        }

结果:

another test
test