8

重複の可能性:
匿名型をメソッドに渡すにはどうすればよいですか?

次のLINQステートメントがありますが、その出力は別のメソッドで処理する必要があります。

var data = from lines in File.ReadAllLines(TrainingDataFile)
                             .Skip(ContainsHeader ? 1 : 0)
           let f = lines.Split(new[] { FieldSeparator }).ToList<String>()
           let target = f[TargetVariablePositionZeroBased]
           select new { F=f, T=target };

このデータを取得するメソッドのパラメータのデータ型は何ですか?

4

3 に答える 3

8

メソッドから匿名データ型を返すことはできません。クラスを定義し、クエリからそのクラスのオブジェクトを返し、それをターゲット メソッドに渡すことができます。

public class SomeClass
{
    public string F {get; set;}
    public string T {get; set;}
}

var data = from lines in File.ReadAllLines(TrainingDataFile)
                                .Skip(ContainsHeader ? 1 : 0)
               let f = lines.Split(new[] { FieldSeparator }).ToList<String>()
               let target = f[TargetVariablePositionZeroBased]
               select new SomeClass { F=f, T=target };

クエリ結果IEnumerable<SomeClass>をパラメーターとしてメソッドに渡すことができます。

public void MethodToCall(IEnumerable<SomeClass> someClass)
{

}

このサンプル コードでIEnumerable<SomeClass>格納されているクエリ結果 ( ) を渡してメソッドを呼び出すにはdata

MethodToCall(data);
于 2013-01-19T15:38:49.633 に答える
3

1) クエリの結果を渡すためだけに、関数をジェネリックにします。

var data = from lines in File.ReadAllLines(TrainingDataFile)
                         .Skip(ContainsHeader ? 1 : 0)
       let f = lines.Split(new[] { FieldSeparator }).ToList<String>()
       let target = f[TargetVariablePositionZeroBased]
       select new { F=f, T=target };

SomeMethod(data);

public void SomeMethod<T>(IEnumerable<T> enumerable)
{
    // ^^choose the return type..
}

単純。メソッド内の処理が非常に単純なものであれば、これで十分です。Fただし、プロパティやTメソッド内にはアクセスできません。

そうするために:

2)ここで Eric が示した「例によるキャスト」トリックを使用できます。彼を引用するには:

メソッドの型推論とローカル変数の型推論を使用して、「これら 2 つのものが同じ型である」ことをコンパイラに伝えます。これにより、匿名型をオブジェクトとしてエクスポートし、匿名型にキャストできます。

...このトリックは、例とソース オブジェクトが同じアセンブリ内のコードで作成された場合にのみ機能します。2 つの異なるアセンブリ内の 2 つの "同一の" 匿名型は、同じ型に統一されません。

SomeMethod(data);

public void SomeMethod(IEnumerable<object> enumerable)
{
    var template = new { F = new List<string>(), T = string.Empty };
    foreach (var item in enumerable)
    {
        var anonymousType = item.CastToTypeOf(template);
        //print string.Join(", ", anonymousType.F) + " - " + anonymousType.T //compiles
        //or whatever
    }
}

//a more generic name perhaps is 'CastToTypeOf' as an extension method
public static T CastToTypeOf<T>(this object source, T example) where T : class
{
    return (T)source;
}

ここでの問題はSomeMethod、メソッド内で特定の型を指定しているため、匿名型に合わせて作成されているため、関数をジェネリックにしないで (可能ですが)、関数に適切な名前を付けることをお勧めします。 .

3)関数が今あなたのユニークなタイプだけのものである場合、それらをすべて単一のメソッドにラップし、まったく渡さないようにすることをお勧めします-面倒なことはありません!:)

4) または、匿名型で実行されるアクションを委任できます。したがって、メソッドの署名は次のようになります。

SomeMethod(data, d => print string.Join(", ", d.F) + " - " + d.T);

public void SomeMethod<T>(IEnumerable<T> enumerable, Action<T> actor)
{
    foreach (var item in enumerable)
        actor(item);
}

重要な場合はFunc、型引数をもう 1 つ持つことでデリゲートも使用できます。

5) それ以外の場合は、匿名型からプロパティを取得するために手間のかかるリフレクションに依存します。

6)dynamicメソッドの引数にキーワードを使用すると、動的型付けができます。上記の両方は、静的型付けの利点を提供しません。

F7)とを保持する別のクラスを用意したほうがよいでしょうT。そして、それは何よりも最高です。しかし、それらが一緒になってエンティティとして何かを表しているか自問してみてください

8) そうでない場合は、問題に応じてIEnumerable<Tuple>orを渡します。IDictionary


それはすべて、メソッドで何を/どのように達成したいかによって異なります。個人的には、趣味のプロジェクトでは (楽しみのために) アプローチ 2 を使用しますが、実稼働コードではコンテキストに応じて 3、4、7、8 を使用します。

于 2013-01-19T15:46:26.623 に答える
3

匿名型を簡単に渡すことはできません。クラスを作成するか、データには 2 つのプロパティしかないため、次のいずれかを使用できTupleます。

select new Tuple<List<string>, string> (f, target);

データ型が正しい場合、パラメーターのデータ型は次のようになります。

IEnumerable<Tuple<List<string>, string>>

プロパティとを参照FTて使用します。TupleItem1Item2

于 2013-01-19T15:40:05.550 に答える