C# LINQ:如何声明 IEnumerable[AnonymousType]?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/901854/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 01:44:05  来源:igfitidea点击:

LINQ: How to declare IEnumerable[AnonymousType]?

c#.netlinq

提问by Ivan Prodanov

This is my function:

这是我的功能:

    private IEnumerable<string> SeachItem(int[] ItemIds)
    {
        using (var reader = File.OpenText(Application.StartupPath + @"\temp\A_A.tmp"))
        {
            var myLine = from line in ReadLines(reader)
                         where line.Length > 1
                         let id = int.Parse(line.Split('\t')[1])
                         where ItemIds.Contains(id)
                         let m = Regex.Match(line, @"^\d+\t(\d+)\t.+?\t(item\[^\t]+\.ddj)")
                         where m.Success == true
                         select new { Text = line, ItemId = id, Path = m.Groups[2].Value };
            return myLine;
        }
    }

I get a compile error,because "myLine" is not a IEnumerable[string] and I don't know how to write IEnumerable[Anonymous]

我收到一个编译错误,因为“myLine”不是 IEnumerable[string] 并且我不知道如何编写 IEnumerable[Anonymous]

"Cannot implicitly convert type 'System.Collections.Generic.IEnumerable[AnonymousType#1]' to 'System.Collections.Generic.IEnumerable[string]'"

“无法将类型 'System.Collections.Generic.IEnumerable[AnonymousType#1]' 隐式转换为 'System.Collections.Generic.IEnumerable[string]'”

采纳答案by Daniel Brückner

You cannot declare IEnumerable<AnonymousType>because the type has no (known) name at build time. So if you want to use this type in a function declaration, make it a normal type. Or just modify your query to return a IENumerable<String>and stick with that type.

您无法声明,IEnumerable<AnonymousType>因为该类型在构建时没有(已知)名称。因此,如果您想在函数声明中使用此类型,请将其设为普通类型。或者只是修改您的查询以返回 aIENumerable<String>并坚持使用该类型。

Or return IEnumerable<KeyValuePair<Int32, String>>using the following select statement.

或者IEnumerable<KeyValuePair<Int32, String>>使用以下 select 语句返回。

select new KeyValuePair<Int32, String>(id, m.Groups[2].Value)

回答by Alexander Kahoun

One thing to remember is that LINQstatements use deferred execution. What that means is that your LINQstatement doesn't actually execute until you either iterate over it in a foreachstatement or you call the .ToList()method on myLine.
For your example try changing:

要记住的一件事是LINQ语句使用延迟执行。这意味着您的LINQ语句实际上不会执行,直到您在foreach语句中对其进行迭代或在 上调用.ToList()方法myLine
对于您的示例,请尝试更改:

return myLine;

To:

到:

return myLine.ToList();

回答by jason

The method signature on SearchItemindicates that the method returns an IEnumerable<string>but the anonymous type declared in your LINQ query is not of type string. If you want to keep the same method signature, you have to change your query to only select strings. e.g.

方法签名SearchItem指示该方法返回 ,IEnumerable<string>但在您的 LINQ 查询中声明的匿名类型不是 type string。如果要保持相同的方法签名,则必须将查询更改为仅选择stringseg

return myLine.Select(a => a.Text);

If you insist on returning the data selected by your query, you can return an IEnumerable<object>if you replace your returnstatement with

如果您坚持返回查询选择的数据,则可以返回 an IEnumerable<object>if 您将return语句替换为

return myLine.Cast<object>();

Then you can consume the objects using reflection.

然后您可以使用反射来使用对象。

But really, if your going to be consuming an anonymous type outside the method that it is declared in, you should define a class an have the method return an IEnumerableof that class. Anonymous types are convenience but they are subject to abuse.

但实际上,如果您要在声明它的方法之外使用匿名类型,您应该定义一个类并让该方法返回该类的一个IEnumerable。匿名类型很方便,但容易被滥用。

回答by jrista

Your function is trying to return IEnumerable<string>, when the LINQ statement you are executing is actually returning an IEnumerable<T> where T is a compile-time generated type. Anonymous types are not always anonymous, as they take on a specific, concrete type after the code is compiled.

您的函数试图返回 IEnumerable<string>,当您正在执行的 LINQ 语句实际上返回一个 IEnumerable<T> 时,其中 T 是编译时生成的类型。匿名类型并不总是匿名的,因为它们在代码编译后采用特定的、具体的类型。

Anonymous types, however, since they are ephemeral until compiled, can only be used within the scope they are created in. To support your needs in the example you provided, I would say the simplest solution is to create a simple entity that stores the results of your query:

然而,匿名类型,因为它们在编译之前是短暂的,只能在它们被创建的范围内使用。 为了支持您提供的示例中的需求,我想说最简单的解决方案是创建一个简单的实体来存储结果您的查询:

public class SearchItemResult
{
    public string Text { get; set; }
    public int ItemId { get; set; }
    public string Path { get; set; }
}

public IEnumerable<SearchItemResult> SearchItem(int[] itemIds)
{
    // ...
    IEnumerable<SearchItemResult> results = from ... select new SearchItemResult { ... }
}

However, if your ultimate goal is not to retrieve some kind of object, and you are only interested in, say, the Path...then you can still generate an IEnumerable<string>:

但是,如果您的最终目标不是检索某种对象,而您只对路径感兴趣……那么您仍然可以生成一个 IEnumerable<string>:

IEnumerable<string> lines = from ... select m.Groups[2].Value;

I hope that helps clarify your understanding of LINQ, enumerables, and anonymous types. :)

我希望这有助于澄清您对 LINQ、枚举和匿名类型的理解。:)

回答by Alex James

I am not necessarily recommending this... It is a kind of subversion of the type system but you could do this:

我不一定推荐这个......它是类型系统的一种颠覆,但你可以这样做:

1) change your method signature to return IEnumerable(the non generic one)

1)将您的方法签名更改为返回IEnumerable(非通用的)

2) add a cast by examplehelper:

2)通过示例助手添加演员表

public static class Extensions{
    public static IEnumerable<T> CastByExample<T>(
            this IEnumerable sequence, 
            T example) where T: class
    {
        foreach (Object o in sequence)
            yield return o as T;
    }
}

3) then call the method something like this:

3)然后像这样调用方法:

var example = new { Text = "", ItemId = 0, Path = "" };
foreach (var x in SeachItem(ids).CastByExample(example))
{
    // now you can access the properties of x 
    Console.WriteLine("{0},{1},{2}", x.Text, x.ItemId, x.Path);
}

And you are done.

你已经完成了。

The key to this is the fact that if you create an anonymous type with the same order, types and property names in two places the types will be reused. Knowing this you can use generics to avoid reflection.

关键在于,如果您在两个地方创建一个具有相同顺序、类型和属性名称的匿名类型,这些类型将被重用。知道了这一点,您可以使用泛型来避免反射。

Hope this helps Alex

希望这有助于亚历克斯

回答by iliketocode

Return a Tupleinstead of an anonymous class. Ex (using "named tuples")-

返回一个Tuple而不是匿名类。Ex(使用“命名元组”)-

(Text: line, ItemId: id, Path: m.Groups[2].Value)

https://docs.microsoft.com/en-us/dotnet/csharp/tuples

https://docs.microsoft.com/en-us/dotnet/csharp/tuples

Instead of-

代替-

new { Text = line, ItemId = id, Path = m.Groups[2].Value }