将C#Covert类型转换为相同类型的IEnumerable?

时间:2018-08-03 19:41:39

标签: c# entity-framework reflection

我有一些方法可以对数据库执行任意SQL,并将该数据集合序列化为具体类型的列表。然后将该数据序列化为JSON并存储在表的单元格中。稍后,我需要返回并将这些数据反序列化为原始数据集,以便可以使用它。

我在解决如何获取Type对象并创建该类型的集合以便反序列化时遇到一些问题。这是我的代码的工作方式:

public async Task ExecuteWidget(Guid runGuid, string widgetName, Type type, string sql,
    IEnumerable<SqlParameter> parameters)
{
    var report = operationsContext.ReportRuns.FirstOrDefault(n => n.RunGuid == runGuid);

    CheckReportStatus(report);

    var param = parameters.ToList();
    var result = edwContext.Database.SqlQuery(type, sql, param.ToArray<object>());
    var query = result.GetQuery(param);
    var data = await result.ToListAsync();
    var widgetData = new ReportRunWidgetData()
    {
        ReportRunId = report?.ReportRunId ?? -1, // This should never be null.
        WidgetName = widgetName,
        WidgetData = new JavaScriptSerializer().Serialize(data),
        Query = query
    };

    operationsContext.ReportRunWidgetDatas.Add(widgetData);
    await operationsContext.SaveChangesAsync();
}

我的提取逻辑如下所示:

public object FetchWidgetData(Guid runGuid, string widgetName, Type dataType)
{
    var data = operationsContext.ReportRuns
        .Include("ReportRunWidgetDatas")
        .FirstOrDefault(n => n.RunGuid == runGuid)?
        .ReportRunWidgetDatas.FirstOrDefault(n => n.WidgetName == widgetName)?
        .WidgetData;

    if (data == null) return null;

    var deserialized = new JavaScriptSerializer().Deserialize(data, dataType);

    return deserialized;
}

现在,当调用ExecuteWidget方法时,type参数由窗口小部件的DTO数据类型填充。例如HeadlineWidgetDTO。但是,execute命令以List<HeadlineWidgetDTO>的形式返回数据。调用我的FetchWidgetData方法时,提供的dataType仍为HeadlineWidgetDTO,但实际上必须为IEnumerable<HeadlineWidgetDTO>类型才能正确反序列化。

仅给出单个数据行的类型,我如何创建Type对象,而不是该类型的集合?

1 个答案:

答案 0 :(得分:3)

这主要是How to use Activator to create an instance of a generic Type and casting it back to that type?的副本,但是很难分辨。

基本上,如果您有类型对象Type theType,则需要执行以下操作:

 var listType = typeof(List<>);
 var typeParams = new [] {theType};
 var listOfTType = listType.MakeGenericType(typeParams);
 var newListOfT = Activator.CreateInstance(listOfTType);

到那时,您拥有类型object的变量,但它引用了类型List<WhateverYourTypeIs>的对象。假设theTypetypeof(int),那么您将得到一个对象List<int>。但是,将其强制转换为可用的东西是另一个问题。如果您想向该列表中添加内容,我怀疑最好的方法是为MethodInfo方法获得一个Add,然后为Invoke获得一个

如果该类型具有默认构造函数且创建起来不太昂贵,我想到了另一种方法。这是一个示例(创建List<int>-但这只是我的编码方式):

  var type = typeof(int);
  var dummy = Activator.CreateInstance(type);
  var listOfType = new[] {dummy}.ToList();

完成后,将listOfType变量键入为List<object>,但引用一个List<int>。它大部分都可以使用-例如,您可以在其上调用Add(object someObj)。您不会获得编译类型参数类型检查,但是可以使用它。