2009-05-23 27 views
22

LINQ:IEnumerable [AnonymousType]を宣言する方法は?

これは私の関数です:

 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 [文字列]ではないため、コンパイルエラーが発生し、IEnumerableの記述方法がわかりません[匿名]

"暗黙のうちに型 'System.Collections.Generic.IEnumerable [AnonymousType#1]'を 'System.Collections.Generic.IEnumerable [string]'に変換します。 ""

答えて

15

タイプはビルド時に何の(既知の)名前を持っていないので、あなたはIEnumerable<AnonymousType>を宣言することはできません。したがって、この型を関数宣言で使用する場合は、通常の型にします。または、クエリを変更してIENumerable<String>を返し、そのタイプに固執してください。

またはIEnumerable<KeyValuePair<Int32, String>>を次のselect文を使用して返します。

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

「新しい{...}を選択」と言うと、AnonymousTypeを作成しました。 –

+0

いいえ、IEnumerableを返し、CastByExampleトリックを使用することもできます。 –

0

一つはLINQ文がdeferred executionを使用することです。つまり、foreachステートメントで繰り返し処理するか、または.ToList()メソッドをmyLineと呼び出すまで、LINQステートメントは実際には実行されません。ご例えば
は変更してみてください:

return myLine; 

へ:

return myLine.ToList(); 
+0

問題はプロシージャ定義であるのに役立ちますので、「プライベートリスト SeachItem(INT []アイテムID)」でなければなりませんが、それはどちらか動作しません。 "暗黙的にタイプを変換できません。 [AnoynymousType#1]をList [string]に一覧表示してください。できない場合は教えてください:) –

8

SearchItem上のメソッドのシグネチャは、メソッドがIEnumerable<string>を返しますが、あなたのLINQクエリで宣言された匿名型の型stringではないことを示しています。同じメソッドシグネチャを保持する場合は、stringを選択するだけでクエリを変更する必要があります。例えば

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

あなたのクエリによって選択されたデータを返すことを主張した場合、あなたは

return myLine.Cast<object>(); 

であなたのreturn文を交換するなら、あなたは、リフレクションを使用してオブジェクトを消費することができIEnumerable<object>を返すことができます。

しかし実際には、宣言されているメソッドの外で匿名型を使用する場合は、そのクラスのIEnumerableを返すクラスを定義する必要があります。匿名型は便利ですが、濫用の対象となります。

5

あなたの機能は、あなたが実行しているLINQ文が実際にTは、コンパイル時に生成タイプであるIEnumerableを<T>を返しているのIEnumerable <文字列>を返すようにしようとしています。匿名型は、コードがコンパイルされた後に特定の具体的な型をとるため、常に匿名型ではありません。

ただし、匿名型はコンパイルするまで一時的であるため、作成されたスコープ内でのみ使用できます。あなたの究極の目標は、いくつかの種類を取得することではない場合、

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 { ... } 
} 

しかし:あなたが提供した例では、あなたのニーズをサポートするために、私は最も簡単な解決策は、クエリの結果を格納し、簡単なエンティティを作成することであると言うでしょう

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

私はLINQ、enumerables、および匿名型のご理解を明確にするのに役立ちます願っています:オブジェクト、あなたはパス、たとえば、のみに関心がある...そして、あなたはまだIEnumerableを<文字列>を生成することができます。 :)私は必ずしもこれを推薦していないです

+1

FYI:匿名型は、作成されたスコープに対して一意であると言うのは厳密ではありません。構造的に匿名型同じ2つの異なるメソッドで使用されるssemblyは、実際にそれらのメソッド間で共有されます。この事実を利用する巧妙な方法がありますが、私はそれらをお勧めしません。 2つのメソッドにまたがって型を共有する必要がある場合は、それを公称にします。 –

+0

マイクロソフトのEric Lippertは有名ですか?今度は鞄を開けたので、猫を出させてください。スコープ間で匿名型をどのように共有しますか? ;) – jrista

+1

非常に注意してください。 goofyメソッド型の推論トリックとキャプチャされた外部変数を使用する必要があります。たぶん、私はしばらくそのブログをやるつもりです。 –

6

... これは、型システムの転覆のようなものですが、あなたはこれを行うこともできます)

1をIEnumerable(非一般的なものを返すために、あなたのメソッドのシグネチャを変更します)

2)cast by exampleヘルパーを追加:

0:このような何かメソッドを呼び出す

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)

これで完了です。

これは、2つの場所で同じ順序、タイプ、およびプロパティ名を持つ匿名タイプを作成すると、タイプが再利用されるという事実です。これを知っていると、ジェネリックを使って反射を避けることができます。

ホープこれは アレックス

+0

賢い。しかし、実際には、誰かがそれほど大変なことに遭遇する場合、宣言されたクラスにデータをカプセル化するだけです。 – jason

+2

私が言ったように、私はこれを推薦していません;) –

+0

...興味深いことに、あなたはこのトラブルに一度しかいません。つまり、ヘルパー拡張メソッドを持っていれば、これは何度も繰り返し使いやすいです。どこでも新しいタイプのローリングとは異なります。 これは、.NET 4.0のタプルの仕事です –

関連する問題