web-dev-qa-db-ja.com

匿名型をパラメーターとして渡す方法は?

匿名型をパラメーターとして他の関数に渡すにはどうすればよいですか?この例を考えてみましょう:

var query = from employee in employees select new { Name = employee.Name, Id = employee.Id };
LogEmployees(query);

ここの変数queryには強い型がありません。 LogEmployees関数を定義してそれを受け入れるにはどうすればよいですか?

public void LogEmployees (? list)
{
    foreach (? item in list)
    {

    }
}

言い換えれば、?マークの代わりに何を使用する必要があります。

122
Saeed Neamati

この匿名型のクラスを作成する必要があると思います。私の意見では、それが最も賢明なことです。しかし、本当にしたくない場合は、ダイナミクスを使用できます。

public void LogEmployees (IEnumerable<dynamic> list)
{
    foreach (dynamic item in list)
    {
        string name = item.Name;
        int id = item.Id;
    }
}

これはnot厳密に型指定されているため、たとえば、NameがEmployeeNameに変更された場合、実行時まで問題があることはわかりません。

157
Tim S.

次のようにできます:

public void LogEmployees<T>(List<T> list) // Or IEnumerable<T> list
{
    foreach (T item in list)
    {

    }
}

...しかし、各アイテムで多くのことを行うことはできません。 ToStringを呼び出すことはできますが、(たとえば)NameおよびIdを直接使用することはできません。

39
Jon Skeet

残念ながら、あなたがやろうとしていることは不可能です。内部では、クエリ変数は匿名型のIEnumerableとして入力されます。匿名型の名前はユーザーコードでは表現できないため、関数への入力パラメーターにする方法はありません。

最善の方法は、型を作成し、それをクエリからの戻り値として使用し、それを関数に渡すことです。例えば、

struct Data {
  public string ColumnName; 
}

var query = (from name in some.Table
            select new Data { ColumnName = name });
MethodOp(query);
...
MethodOp(IEnumerable<Data> enumerable);

ただし、この場合、選択するフィールドは1つだけなので、フィールドを直接選択する方が簡単な場合があります。これにより、フィールドタイプのIEnumerableとしてクエリが入力されます。この場合、列名。

var query = (from name in some.Table select name);  // IEnumerable<string>
18
JaredPar

パラメータタイプがobjectでない限り、匿名タイプを非ジェネリック関数に渡すことはできません。

public void LogEmployees (object obj)
{
    var list = obj as IEnumerable(); 
    if (list == null)
       return;

    foreach (var item in list)
    {

    }
}

匿名型は、メソッド内での短期間の使用を目的としています。

MSDNから- 匿名型

フィールド、プロパティ、イベント、またはメソッドの戻り値の型を匿名型として宣言することはできません。同様に、メソッド、プロパティ、コンストラクター、またはインデクサーの仮パラメーターを匿名型として宣言することはできません。 匿名型または匿名型を含むコレクションをメソッドの引数として渡すには、パラメータを型オブジェクトとして宣言できます。ただし、これを行うと、厳密な型指定の目的が無効になります。

(エンファシス鉱山)


更新

ジェネリックを使用して、目的を達成できます。

public void LogEmployees<T>(IEnumerable<T> list)
{
    foreach (T item in list)
    {

    }
}
10
Oded

通常、これはジェネリックで行います。たとえば、次のとおりです。

MapEntToObj<T>(IQueryable<T> query) {...}

コンパイラは、MapEntToObj(query)を呼び出すときにTを推測する必要があります。メソッド内で何をしたいのかよくわからないので、これが便利かどうかわかりません...問題はMapEntToObj内でTに名前を付けることができないことです-あなたは次のいずれかができます:

  • Tを使用して他の汎用メソッドを呼び出します
  • Tでリフレクションを使用して物事を行う

しかし、それ以外では、匿名型を操作するのは非常に困難です-特に不変であるためです;-p

別のトリック(extracting dataの場合)は、セレクターも渡すことです-つまり、次のようなものです:

Foo<TSource, TValue>(IEnumerable<TSource> source,
        Func<TSource,string> name) {
    foreach(TSource item in source) Console.WriteLine(name(item));
}
...
Foo(query, x=>x.Title);
7
Marc Gravell

次のトリック(ジェネリック型へのキャスト)でジェネリックを使用できます。

public void LogEmployees<T>(IEnumerable<T> list)
{
    foreach (T item in list)
    {
        var typedItem = Cast(item, new { Name = "", Id = 0 });
        // now you can use typedItem.Name, etc.
    }
}

static T Cast<T>(object obj, T type)
{
    return (T)obj;
}
6

「動的」もこの目的に使用できます。

var anonymousType = new { Id = 1, Name = "A" };

var anonymousTypes = new[] { new { Id = 1, Name = "A" }, new { Id = 2, Name = "B" };

private void DisplayAnonymousType(dynamic anonymousType)
{
}

private void DisplayAnonymousTypes(IEnumerable<dynamic> anonymousTypes)
{
   foreach (var info in anonymousTypes)
   {

   }
}
6
Dinesh Kumar P

匿名タイプを渡す代わりに、動的タイプのリストを渡します。

  1. var dynamicResult = anonymousQueryResult.ToList<dynamic>();
  2. メソッドシグネチャ:DoSomething(List<dynamic> _dynamicResult)
  3. メソッドの呼び出し:DoSomething(dynamicResult);
  4. できた。

Petar Ivanov に感謝!

2
usefulBee

結果が特定のインターフェイスを実装していることがわかっている場合、そのインターフェイスをデータ型として使用できます。

public void LogEmployees<T>(IEnumerable<T> list)
{
    foreach (T item in list)
    {

    }
}
0
Alex

引数の型としてIEnumerable<object>を使用します。しかし、避けられない明示的なキャストにとっては大きな利益ではありません。乾杯

0
Mario Vernari