6

いくつかの異なる型付きリストがあり、それらに参加して動的な結果を取得したいと思います。

list1がベースリストであるとしましょう。リスト2と3は、追加情報を含むリストです。時々私は情報が欲しいです、そして他の実行では私はそれら(の1つ)を必要としません。

追加情報が必要な場合は、取得する列がわかります。

public struct DateAndValue1
{
   public uint DBDate { get; set; }
   public double Value1 { get; set; }
}

public struct DateAndValue2
{
   public uint DBDate { get; set; }
   public double Value1 { get; set; }
   public bool myBool { get; set; }
   public int someInt { get; set; }
}

List<DateAndValue1> list1,list2;
List<DateAndValue2> list3;

bool addList2, addList3;
list1 = new List<DateAndValue1>();
list1.Add(new DateAndValue1 { DBDate = 1, Value1 = 10 });
list1.Add(new DateAndValue1 { DBDate = 2, Value1 = 20 });
list1.Add(new DateAndValue1 { DBDate = 3, Value1 = 30 });
list1.Add(new DateAndValue1 { DBDate = 4, Value1 = 40 });
list1.Add(new DateAndValue1 { DBDate = 5, Value1 = 50 });
list1.Add(new DateAndValue1 { DBDate = 6, Value1 = 60 });

list2 = new List<DateAndValue1>();
list2.Add(new DateAndValue1 { DBDate = 1, Value1 = 100 });
list2.Add(new DateAndValue1 { DBDate = 1, Value1 = 200 });
list2.Add(new DateAndValue1 { DBDate = 3, Value1 = 300 });
list2.Add(new DateAndValue1 { DBDate = 4, Value1 = 400 });
list2.Add(new DateAndValue1 { DBDate = 5, Value1 = 500 });
list2.Add(new DateAndValue1 { DBDate = 5, Value1 = 600 });

list3 = new List<DateAndValue2>();
list3.Add(new DateAndValue2 { DBDate = 1, Value1 = 1000, myBool = true });
list3.Add(new DateAndValue2 { DBDate = 2, Value1 = 2000, myBool = true });
list3.Add(new DateAndValue2 { DBDate = 2, Value1 = 3000, myBool = true });
list3.Add(new DateAndValue2 { DBDate = 4, Value1 = 4000, myBool = true });
list3.Add(new DateAndValue2 { DBDate = 6, Value1 = 5000, myBool = true });
list3.Add(new DateAndValue2 { DBDate = 6, Value1 = 6000, myBool = true });

リスト1と2の両方の情報が必要であると仮定します。

List<dynamic> result = (from a in list1
                        join b in list2
                        on a.DBDate equals b.DBDate
                        select new { DBDate = a.DBDate, Result_A1 = a.Value1, Result_B1 = b.Value1 }).ToList<dynamic>();

リスト3の情報が必要になる場合があります(trueの場合、常に結果に追加されます)。

if(true)
{
    result = (from so_far in result
              join c in list3
              on so_far.a.DBDate equals c.DBDate
              select new {so_far, Result_C1 = c.Value1,Result_C2=c.myBool }).ToList<dynamic>();
}

これは機能しますが、aとbの結果が1つの列に結合されます。ジョイントであるかどうかに関係なく、約10個のリスト(これもさまざまなタイプ)を使用するため、最終結果を知ることは非常に困難であり、したがって次のようになります。

result = (from so_far in result
        join c in list3
        on so_far.a.DBDate equals c.DBDate
        select new {DBDate= so_far.DBDate, Result_A1=so_far.Result_A1,Result_B1=so_far.Result_B1 , Result_C1 = c.Value1,Result_C2=c.myBool }).ToList<dynamic>();

異なる列で利用可能なすべての結果を動的に取得するにはどうすればよいですか。できれば、結合されたすべてのリストのDBDDateをスキップして、DBDateが1つの列に収まるようにします。よろしく、

Matthijs

================================================== ==========

追加情報(コード)結果を読みやすくしようとしました:

public DataTable LINQToDataTable<T>(IEnumerable<T> varlist)
    {
            DataTable dtReturn = new DataTable();

            PropertyInfo[] columnNames = null;

            if(varlist == null)
                return dtReturn;

            try
            {
                foreach(T rec in varlist)
                {
                    if(columnNames == null)
                    {
                        columnNames = ((Type)rec.GetType()).GetProperties();
                        foreach(PropertyInfo pi in columnNames)
                        {
                            Type colType = pi.PropertyType;

                            if((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>)))
                            {
                                colType = colType.GetGenericArguments()[0];
                            }

                            dtReturn.Columns.Add(new DataColumn(pi.Name, colType));
                        }
                    }

                    DataRow dr = dtReturn.NewRow();

                    foreach(PropertyInfo pi in columnNames)
                    {
                        dr[pi.Name] = pi.GetValue(rec, null) == null ? DBNull.Value : pi.GetValue
                        (rec, null);
                    }

                    dtReturn.Rows.Add(dr);
                }
            }
            catch
            {
                return dtReturn;
            }
            return dtReturn;
    }

そしてこれを試しました:

        private class NestedPropertyInfo
    {
        public PropertyInfo Parent { get; set; }
        public PropertyInfo Child { get; set; }
        public string Name { get { return Parent.Name + "_" + Child.Name; } }
    }

    public DataTable LINQMultipleSelectToDataTable<T>(IEnumerable<T> varlist)
    {
        DataTable dtReturn = new DataTable();
        NestedPropertyInfo[] columns = null;

        if(varlist == null)
            return dtReturn;

        foreach(T rec in varlist)
        {
            if(columns == null)
            {
                columns = (
                    from p1 in rec.GetType().GetProperties()
                    from p2 in p1.PropertyType.GetProperties()
                    select new NestedPropertyInfo { Parent = p1, Child = p2 }
                    ).ToArray();

                foreach(var column in columns)
                {
                    var colType = column.Child.PropertyType;

                    if((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>)))
                    {
                        colType = colType.GetGenericArguments()[0];
                    }

                    dtReturn.Columns.Add(new DataColumn(column.Name, colType));
                }
            }

            DataRow dr = dtReturn.NewRow();

            foreach(var column in columns)
            {
                var parentValue = column.Parent.GetValue(rec, null);
                var childValue = parentValue == null ? null : column.Child.GetValue(parentValue, null);
                dr[column.Name] = childValue ?? DBNull.Value;
            }

            dtReturn.Rows.Add(dr);
        }

        return dtReturn;
    }
4

1 に答える 1

2

これを行う簡単な方法はありません。

とにかくそれをキャストしているので、いくつかのヘルパーメソッドと一緒にdynamic利用することができます。ExpandoObject

次のヘルパーが必要になります。

public dynamic GetFlatExpando(object o)
{
    IDictionary<string, object> result = new ExpandoObject();

    foreach(var property in o.GetType().GetProperties())
    {
        var value = property.GetValue(o, null);
        var expando = value as ExpandoObject;
        if(expando == null)
            result[property.Name] = value;
        else
            expando.CopyInto(result);
    }

    return result;
}

public static class Extensions
{
    public static void CopyInto(this IDictionary<string, object> source,
                                IDictionary<string, object> target)
    {
        foreach(var member in source)
        {
            target[member.Key] = member.Value;
        }
    }
}

そして、それよりも、すべてのクエリで.Select(GetFlatExpando)への呼び出しの前に使用するだけです。ToList

List<dynamic> result = (from a in list1
                        join b in list2
                        on a.DBDate equals b.DBDate
                        select new { DBDate = a.DBDate, Result_A1 = a.Value1,
                                     Result_B1 = b.Value1 })
                        .Select(GetFlatExpando)
                        .ToList<dynamic>();

if(true)
{
    result = (from so_far in result
              join c in list3
              on so_far.DBDate equals c.DBDate
              select new {so_far, Result_C1 = c.Value1,Result_C2=c.myBool })
              .Select(GetFlatExpando)
              .ToList<dynamic>();
}

このコードには、一度だけ存在する素晴らしい副作用がありDBDateます。

Extensionsデータグリッドへのバインドを機能させるには、別の拡張メソッドが必要です(上からクラスに入れます)。

public static DataTable ToDataTable(this IEnumerable<IDictionary<string, object>> source)
{
    var result = new DataTable();

    foreach(var rowData in source)
    {
        var row = result.NewRow();

        if(result.Columns.Count == 0)
        {
            foreach(var columnData in rowData)
            {
                var column = new DataColumn(columnData.Key,
                                            columnData.Value.GetType())
                result.Columns.Add(column);
            }
        }

        foreach(var columnData in rowData)
            row[columnData.Key] = columnData.Value;
        result.Rows.Add(row);
    }

    return result;
}

次のように使用します。

var dataTable = result.Cast<IDictionary<string, object>>()
                      .ToDataTable();
于 2012-12-13T15:01:50.047 に答える