C# - Yield 给出了不可用的类型

发布于 2024-08-16 14:55:03 字数 3126 浏览 6 评论 0原文

我有一个类和一组 IEnumerables,它们使用该类为我提供列表中的列表。 (有关详细信息,请参阅此问题的答案。)

这是代码:

public IEnumerable<IEnumerable<WorkItemColumn>> EnumerateResultSet(WorkItemCollection queryResults)//DisplayFieldList displayFieldList)
{
    foreach (WorkItem workItem in queryResults)
    {
        yield return EnumerateColumns(queryResults.DisplayFields, workItem);   
    }
}

public IEnumerable<WorkItemColumn> EnumerateColumns(DisplayFieldList resultSet, WorkItem workItem)
{
    foreach (FieldDefinition column in resultSet)
        yield return new WorkItemColumn { Name = column.Name, Value = workItem[column.Name], WorkItemForColumn = workItem};
}

和类:

public class WorkItemColumn
{
    public string Name { get; set; }
    public object Value { get; set; }
    public WorkItem WorkItemForColumn { get; set; }
}

我将此结果设置为列表框的 ItemsSource

Form.QueryResultListSource = EnumerateResultSet(queryResults);

当我尝试捕获此列表框的事件时,就会出现问题:

public void QueryResultsSelectionChanged(SelectionChangedEventArgs e)
{
                                                   +-----------------+
                                                   v                 | 
    foreach (WorkItemColumn workItemColumn in e.AddedItems)          |
    {                                                                |
        AddWorkItemToPad(workItemColumn.WorkItemForColumn);          |
    }                                                +---------------|
                                                     |               |
                                                     v               |    
    foreach (WorkItemColumn workItemColumn in e.RemovedItems)        |
    {                                                                |
        RemoveWorkItemFromPad(workItemColumn.WorkItemForColumn);     |
    }                                                                |
                                                                     |    
}                                                                    |
                                                                     |
These items are where the problem is --------------------------------+

当我在调试时检查 e.AddedItems[0] 时,它说它的类型是 EnumerateColumns 。

当我尝试转换为该类型时,Visual Studio 说(可以理解)EnumerateColumns 是一种方法,但像类型一样使用。

那么,我如何按类型引用它,以便我可以执行 foreach 循环并获取其中的内容?


这是我根据答案更新的代码:

public void QueryResultsSelectionChanged(SelectionChangedEventArgs e)
{
    foreach (IEnumerable<WorkItemColumn> workItemColumns in e.AddedItems)
    {
        if (workItemColumns.Count() > 0)
            AddWorkItemToPad(workItemColumns.First().WorkItemForColumn);                
    }

    foreach (IEnumerable<WorkItemColumn> workItemColumns in e.RemovedItems)
    {
        if (workItemColumns.Count() > 0)
            RemoveWorkItemFromPad(workItemColumns.First().WorkItemForColumn);    
    }
}

I have a class and a set of IEnumerables that are using this class to give me a list in a list. (See this question's answer for details.)

Here is the code:

public IEnumerable<IEnumerable<WorkItemColumn>> EnumerateResultSet(WorkItemCollection queryResults)//DisplayFieldList displayFieldList)
{
    foreach (WorkItem workItem in queryResults)
    {
        yield return EnumerateColumns(queryResults.DisplayFields, workItem);   
    }
}

public IEnumerable<WorkItemColumn> EnumerateColumns(DisplayFieldList resultSet, WorkItem workItem)
{
    foreach (FieldDefinition column in resultSet)
        yield return new WorkItemColumn { Name = column.Name, Value = workItem[column.Name], WorkItemForColumn = workItem};
}

And the class:

public class WorkItemColumn
{
    public string Name { get; set; }
    public object Value { get; set; }
    public WorkItem WorkItemForColumn { get; set; }
}

I set this result to be the ItemsSource for my ListBox

Form.QueryResultListSource = EnumerateResultSet(queryResults);

The problem hits when I try to catch an event for this list box:

public void QueryResultsSelectionChanged(SelectionChangedEventArgs e)
{
                                                   +-----------------+
                                                   v                 | 
    foreach (WorkItemColumn workItemColumn in e.AddedItems)          |
    {                                                                |
        AddWorkItemToPad(workItemColumn.WorkItemForColumn);          |
    }                                                +---------------|
                                                     |               |
                                                     v               |    
    foreach (WorkItemColumn workItemColumn in e.RemovedItems)        |
    {                                                                |
        RemoveWorkItemFromPad(workItemColumn.WorkItemForColumn);     |
    }                                                                |
                                                                     |    
}                                                                    |
                                                                     |
These items are where the problem is --------------------------------+

When I examine e.AddedItems[0] while debugging and it says its type is EnumerateColumns.

When I try cast to that type Visual Studio says (understandably) that EnumerateColumns is a method but is used like a type.

So, how can I reference this by type so I can do a foreach loop and get at the stuff inside it?


This was my updated code based on the answer:

public void QueryResultsSelectionChanged(SelectionChangedEventArgs e)
{
    foreach (IEnumerable<WorkItemColumn> workItemColumns in e.AddedItems)
    {
        if (workItemColumns.Count() > 0)
            AddWorkItemToPad(workItemColumns.First().WorkItemForColumn);                
    }

    foreach (IEnumerable<WorkItemColumn> workItemColumns in e.RemovedItems)
    {
        if (workItemColumns.Count() > 0)
            RemoveWorkItemFromPad(workItemColumns.First().WorkItemForColumn);    
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

清醇 2024-08-23 14:55:03

问题是您的第一个方法不会产生第一个方法给出的每个结果 - 它会产生可枚举本身。编译器为迭代器生成的类型的类型 - 但重要的是,它实现 IEnumerable

如果需要,您可以将每个项目强制转换为 IEnumerable - 但目前还不清楚您要在 QueryResultsSelectionChanged 中执行的操作。您可能想做:

foreach (IEnumerable<WorkItemColumn> workItemColumns in e.AddedItems)
{                                                   
    foreach(WorkItemColumn workItemColumn in workItemColumns)
    {
        AddWorkItemToPad(workItemColumn.WorkItemForColumn); 
    }
}

等等...或者您可能不想做。在不知道自己真正想做什么的情况下说出来是很棘手的。不管怎样,问题的关键在于您当前正在尝试将一系列项目视为单个项目。不要这样做:)

The problem is that your first method isn't yielding each result given by the first - it's yielding the enumerable itself. The type of that a compiler-generated type for the iterator - but importantly, it implements IEnumerable<WorkItemColumn>.

You can cast each item to IEnumerable<WorkItemColumn> if you want - but it's not really clear what you're trying to do in QueryResultsSelectionChanged. You may want to do:

foreach (IEnumerable<WorkItemColumn> workItemColumns in e.AddedItems)
{                                                   
    foreach(WorkItemColumn workItemColumn in workItemColumns)
    {
        AddWorkItemToPad(workItemColumn.WorkItemForColumn); 
    }
}

etc... or you may not. It's tricky to say without knowing what you're really trying to do. Anyway, the crux of it is that you're currently trying to treat a sequence of items as a single item. Don't do that :)

并安 2024-08-23 14:55:03

e.AddedItems[0] 是编译器生成的隐藏迭代器类型的实例,您不能直接使用它。
但是,它实现了 IEnumerable,因此您可以通过该接口使用它。

换句话说:

foreach (IEnumerable<WorkItemColumn> colSet in e.RemovedItems)        
    foreah(WorkItemColumn workItemColumn in colSet)
        RemoveWorkItemFromPad(workItemColumn.WorkItemForColumn);     

e.AddedItems[0] is an instance of a hidden iterator type generated by the compiler, which you cannot use directly.
However, it implements IEnumerable<WorkItemColumn>, so you can use it through that interface.

In other words:

foreach (IEnumerable<WorkItemColumn> colSet in e.RemovedItems)        
    foreah(WorkItemColumn workItemColumn in colSet)
        RemoveWorkItemFromPad(workItemColumn.WorkItemForColumn);     
情定在深秋 2024-08-23 14:55:03

尽管使用迭代器可能不是解决此问题的最佳方法,但您可能可以通过将枚举存储在数组中来避免遇到的问题,如下所示:

using System.Linq;
...
Form.QueryResultListSource = EnumerateResultSet(queryResults).ToArray();

并将您的 EnumerateResultSet 更改为如下所示:

public IEnumerable<WorkItemColumn[]> EnumerateResultSet(WorkItemCollection queryResults)//DisplayFieldList displayFieldList) 
{ 
    foreach (WorkItem workItem in queryResults) 
    { 
        yield return EnumerateColumns(queryResults.DisplayFields, workItem).ToArray();    
    } 
} 

正如其他人所指出的,使用yield关键字,您实际上返回一个知道如何迭代您想要枚举的项目的函数。但是将数据源设置为此可枚举并不简单地执行一次并存储结果。使用迭代器可能会遇到很多性能问题,因为每当需要使用结果时,都需要重新执行迭代。

Although using an iterator is probably not the best approach for this problem, you can probably avoid the problem you're experiencing by storing the enumeration in an array like so:

using System.Linq;
...
Form.QueryResultListSource = EnumerateResultSet(queryResults).ToArray();

And change your EnumerateResultSet to look like:

public IEnumerable<WorkItemColumn[]> EnumerateResultSet(WorkItemCollection queryResults)//DisplayFieldList displayFieldList) 
{ 
    foreach (WorkItem workItem in queryResults) 
    { 
        yield return EnumerateColumns(queryResults.DisplayFields, workItem).ToArray();    
    } 
} 

As others have noted, using the yield keyword you are effectively returning a function that knows how to iterate over the items you wish to enumerate. But setting a data source to this enumerable does not simply execute it once and store the results. You'll likely have lots of performance problems by using iterators because anytime the results need to be used, the iteration needs to be performed all over again.

妞丶爷亲个 2024-08-23 14:55:03

为了完整起见,您确实应该包含 AddedItemsRemovedItems 的相关代码。

尽管如此,请以完全限定的形式(意味着包括命名空间)来转换具有类型名称的对象。这将使其绑定到类型而不是方法签名,因为该方法在类型级别不可用,但子类型可以。

In the interest of completeness, you really should include the relevant code for AddedItems and RemovedItems.

Nonetheless, cast the object with the type name in fully-qualified form (meaning namespace included). This will make it bind to the type rather than the method signature, since the method won't be available at the type level but the subtype will.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文