这是我的功能:
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;
}
}
我收到编译错误,因为“myLine”不是IEnumerable [string]而且我不知道怎么写IEnumerable [匿名]
“无法将类型'System.Collections.Generic.IEnumerable [AnonymousType#1]'隐式转换为'System.Collections.Generic.IEnumerable [string]'”
答案 0 :(得分:15)
您无法声明IEnumerable<AnonymousType>
,因为该类型在构建时没有(已知)名称。因此,如果要在函数声明中使用此类型,请将其设置为普通类型。或者只是修改您的查询以返回IENumerable<String>
并坚持使用该类型。
或使用以下select语句返回IEnumerable<KeyValuePair<Int32, String>>
。
select new KeyValuePair<Int32, String>(id, m.Groups[2].Value)
答案 1 :(得分:10)
我不一定推荐这个...... 它是类型系统的一种颠覆,但你可以这样做:
1)更改方法签名以返回IEnumerable
(非通用签名)
2)添加cast by example助手:
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)然后调用这样的方法:
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);
}
你已经完成了。
关键是,如果您在两个地方创建具有相同顺序,类型和属性名称的匿名类型,则将重用这些类型。知道了这一点,你可以使用泛型来避免反思。
希望这会有所帮助 亚历
答案 2 :(得分:9)
SearchItem
上的方法签名表示该方法返回IEnumerable<string>
,但在LINQ查询中声明的匿名类型不是string
类型。如果要保留相同的方法签名,则必须将查询更改为仅选择string
s。 e.g。
return myLine.Select(a => a.Text);
如果您坚持要求退回查询选择的数据,则可以在用{/ 1>替换IEnumerable<object>
语句时返回return
return myLine.Cast<object>();
然后你可以使用反射消耗对象。
但实际上,如果你要在声明它的方法之外使用匿名类型,你应该定义一个类,让该方法返回该类的IEnumerable
。匿名类型很方便,但它们会受到滥用。
答案 3 :(得分:5)
当您正在执行的LINQ语句实际返回IEnumerable&lt; T&gt;时,您的函数正在尝试返回IEnumerable&lt; string&gt;其中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 { ... }
}
但是,如果您的最终目标不是检索某种对象,并且您只对Path ...感兴趣,那么您仍然可以生成IEnumerable&lt; string&gt;:
IEnumerable<string> lines = from ... select m.Groups[2].Value;
我希望这有助于澄清您对LINQ,enumerables和匿名类型的理解。 :)
答案 4 :(得分:0)
要记住的一件事是LINQ
语句使用deferred execution。这意味着,只有在LINQ
语句中对foreach
语句进行迭代或在.ToList()
上调用myLine
方法时,return myLine;
语句才会实际执行。 />
对于您的示例,请尝试更改:
return myLine.ToList();
要:
{{1}}
答案 5 :(得分:0)
返回Tuple
而不是匿名类。 Ex(使用“命名元组”)-
(Text: line, ItemId: id, Path: m.Groups[2].Value)
https://docs.microsoft.com/en-us/dotnet/csharp/tuples
代替-
new { Text = line, ItemId = id, Path = m.Groups[2].Value }