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

C# LINQ:如何声明IEnumerable[AnonymousType]?,c#,.net,linq,C#,.net,Linq,这是我的职责: private IEnumerable<string> SeachItem(int[] ItemIds) { using (var reader = File.OpenText(Application.StartupPath + @"\temp\A_A.tmp")) { var myLine = from line in ReadLines(reader)

这是我的职责:

    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;
        }
    }
private IEnumerable SeachItem(int[]ItemIds)
{
使用(var reader=File.OpenText(Application.StartupPath+@“\temp\A_A.tmp”))
{
var myLine=从读取行中的行(读卡器)
其中line.Length>1
让id=int.Parse(line.Split('\t')[1])
其中ItemIds.Contains(id)
让m=Regex.Match(行@“^\d+\t(\d+\t.+?\t(项\\[^\t]+\.ddj)”)
其中m.Success==true
选择新{Text=line,ItemId=id,Path=m.Groups[2].Value};
返回糜棱线;
}
}
我得到一个编译错误,因为“myLine”不是IEnumerable[string],我不知道如何编写IEnumerable[Anonymous]


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

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

return myLine;
致:


无法声明
IEnumerable
,因为该类型在生成时没有(已知)名称。因此,如果要在函数声明中使用此类型,请将其设置为普通类型。或者只需修改查询以返回
IENumerable
,并坚持使用该类型

或者使用以下select语句返回
IEnumerable

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

SearchItem上的方法签名表示该方法返回一个
IEnumerable
,但LINQ查询中声明的匿名类型不是
字符串类型
。如果要保留相同的方法签名,必须将查询更改为仅选择
string
s。e、 g

return myLine.Select(a => a.Text);
如果坚持返回查询选择的数据,如果将
return
语句替换为

return myLine.Cast<object>();
返回myLine.Cast();
然后可以使用反射来使用对象


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

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

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

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 { ... }
}
公共类SearchItemResult
{
公共字符串文本{get;set;}
公共int ItemId{get;set;}
公共字符串路径{get;set;}
}
公共IEnumerable SearchItem(int[]ItemId)
{
// ...
IEnumerable results=from…选择新的SearchItemResult{…}
}
但是,如果您的最终目标不是检索某种对象,并且您只对路径感兴趣,那么您仍然可以生成IEnumerable:

IEnumerable line=来自。。。选择m.Groups[2]。值;

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

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

1) 将方法签名更改为返回
IEnumerable
(非泛型签名)

2) 添加帮助程序:

你就完了

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

希望这有帮助
Alex

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

而不是-

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

ValueTuple
是C#version 7的一部分,最初作为一个单独的NuGet包(System.ValueTuple)实现。从.NET4.7开始,它是一种内置类型。对于.NET Core,2.0之前的版本需要NuGet包,但它是2.0版本内置的。

问题在于过程定义,因此它应该是“私有列表SeachItem(int[]ItemIds)”,但这也不起作用。“无法隐式地将类型List[AnoynyCustomType#1]转换为List[string]。如果这是不可能做到的,请告诉我。:)当你说“选择新{…}”“,您创建了一个匿名类型。如果选择一个字符串,那么它应该可以工作。否,但是您可以返回IEnumerable并使用CastByExample技巧。但不推荐。聪明。但实际上,如果有人会遇到那么多麻烦,他们应该将数据封装在一个声明的类中。。。有趣的是,您只会遇到一次这样的问题,即一旦您有了helper扩展方法,这就很容易一次又一次地使用。不同于到处滚动的新类型。无论如何,这是.NET 4.0FYI中Tuple的工作:说匿名类型在创建它们的作用域中是唯一的并不是严格正确的。在同一程序集中结构等效但在两个不同方法中使用的匿名类型实际上在这些方法中共享。有一些聪明的方法可以利用这一事实,但我不推荐它们;如果你需要在两种方法中共享一个类型,那么就让它成为名义上的。是微软fame的Eric Lippert吗?
IEnumerable<string> lines = from ... select m.Groups[2].Value;
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;
    }
}
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);
}
(Text: line, ItemId: id, Path: m.Groups[2].Value)
new { Text = line, ItemId = id, Path = m.Groups[2].Value }