【问题标题】:LINQ join and orderby issuesLINQ join 和 orderby 问题
【发布时间】:2013-07-05 20:01:11
【问题描述】:

好的,这几天我一直在努力解决这个问题,在学习了 LINQ 之后,我认为我走在了正确的轨道上。但我有一个 SQL 大脑,有时很难将其转换为 C#。

我有两个数组,一个按字母顺序排序,另一个按 ID 排序。我需要按字母顺序排列第二个数组。 ID 是连接因素。 IE。 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 的排序版本。

编辑:当我将鼠标悬停在“加入”上时,我得到“方法'IEnumerable System.Linq.Enumerable.Join(this Enumerable,IEnumerable,Func,Func...'的类型参数不能从查询中推断出来. 我现在正在研究。

感谢收看!

【问题讨论】:

  • 将join中的a改为a.ID
  • @newStackExchangeInstance - 我改为:在 a.ID 上的 _priceLevels 中加入 p 等于 p.ID,a.ID 中的 a 现在也是红色的。这让我很困惑,因为我应该能够引用 ArrayList 的那个字段。
  • 我认为你需要在最后选择一个
  • 使用强类型 List<T> 而不是数组列表,现在应该可以解决了。

标签: c# linq c#-4.0


【解决方案1】:

当我将鼠标悬停在“加入”上时,我得到“无法从查询中推断出方法 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都可以转换为int,所以int获胜,第二个密钥会自动转换为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。

【讨论】:

  • 这是一个非常有用的答案,谢谢。现在我正在与类型作斗争,但我会明白的。我试图弄清楚如何将我的 ArrayList 和 IGenericListItem 转换为相同的类型。谢谢!
  • @BClaydon:这两个序列不需要是同一类型。它们需要是通用序列类型,即IEnumerable<something>,但两个“东西”可以不同。 键选择器类型需要相同。这样想:如果您有一个客户列表和一个订单列表,那么这两个列表属于不同类型就可以了:客户和订单。但是加入列表的选择器必须相同:例如,客户有一个字段 Id,一个订单有一个字段 CustomerId——连接键类型必须在双方相同。
【解决方案2】:

你的select子句错了,应该是这样的:

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

另一个问题是_assignmentControlsArrayList类型的,它有Object类型的元素,所以编译器不知道a的实际类型,不能用它作为join因为a 的类型与p.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;

【讨论】:

  • 你是对的,我忽略了这个,但 _assignmentControls 确实有对象。它实际上包含 _priceLevels 的副本,这非常令人讨厌。受保护的 ArrayList _assignmentControls = new ArrayList(); _assignmentControls 的形式为 {ID, LastPrice, NewPrice, _priceLevels[]} {1, 1.00, 2.00, _priceLevels} {2, 1.00, 2.00, _priceLevels} {3, 1.00, 2.00, _priceLevels} 之前我尝试只使用 _assignmentControls并使用它的 _priceLevels 子数组,但也无法弄清楚。 _priceLevels 也是我认为我使用该变量的局部变量。
【解决方案3】:

我认为你应该写:

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

当您从 _assignmentControls 中写入时 - 您正在声明一个变量,该变量引用要对其执行操作的序列中的当前元素。当您调用 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-25
    相关资源
    最近更新 更多