使用反射在运行时为dapper querymultiple Read方法动态创建类型



我试图在运行时动态传递类的类型。下面的代码给出了代码段的错误:

    object newObject Activator.CreateInstance(Type.GetType(t.GetGenericArguments()[0].FullName));
    data.Read<newObject>();

我也试过

    data.Read<Type.GetType(t.GetGenericArguments()[0].FullName)>();  
下面是完整的方法:
    public object FetchMultipleRecordSet(string storedProcedure, IList<QueryParameter> parameterCollection, object dataList)
    {
        if (!string.IsNullOrEmpty(storedProcedure))
        {
            using (SqlConnection sql = CreateDatabaseConnection())
            {
                DynamicParameters dynamicParameter = ConvertToDynamicParameters(parameterCollection);
                var data = sql.QueryMultiple(storedProcedure, dynamicParameter, null, null, commandType: CommandType.StoredProcedure);
                PropertyInfo[] properties = dataList.GetType().GetProperties();
                foreach (PropertyInfo property in properties)
                {
                    Type t = property.PropertyType;
                    if (t.BaseType == null && t.IsGenericType && t.Namespace == "System.Collection.Generic")
                    {
                        //property.SetValue(data.Read());
                        object newObject = Activator.CreateInstance(Type.GetType(t.GetGenericArguments()[0].FullName));
                        data.Read<>();    
                    }
                    else if (t.Namespace != "System")
                    {
                        //typeCollection.Add(Type.GetType(t.FullName));
                    }
                }
            }
        }
        return dataList;
    }

这是我想使用的视图模型:

    public class ResultCollection
    {
        public IList<ShortCodeList> ShortCodeListCollection { get; set; }
        public DateTime CurrentDate { get; set; }
        public UserMembershipPlan UserMembershipPlanRecord { get; set; }
        public IList<EmailRecipients> EmailRecipientsCollection { get; set; }
    }

我需要将类型传递给data.Read(),以便可以将泛型形式的属性映射到结果集。如果我传递"newObject"或"Type.GetType(t.GetGenericArguments()[0]. fullname)",它仍然会给我错误。这可能看起来笨拙,但我认为它应该工作。

目前,dapper的类型化API使用泛型。有一个未类型化的API,但您需要自己进行成员映射。要通过类型调用泛型方法,需要在泛型方法上使用MethodInfo、MakeGenericMethod和Invoke。还有一种方法可以通过dynamic欺骗它,通过在代码中添加shim方法,类似于:

dynamic template = ...  // activator etc
Evil(template, otherArgs...);
Evil<T>(T template, otherArgs...) {
    use some <T> method etc here
}

作为一个更完整的例子,如下所示:

public void TypeBasedViaDynamic()
{
    Type type = GetSomeType();
    dynamic template = Activator.CreateInstance(type);
    dynamic actual = CheetViaDynamic(template,
        "select @A as [A], @B as [B]", new { A = 123, B = "abc" });
    ((object)actual).GetType().IsEqualTo(type);
    int a = actual.A;
    string b = actual.B;
    a.IsEqualTo(123);
    b.IsEqualTo("abc");
}
T CheetViaDynamic<T>(T template, string query, object args)
{
    return connection.Query<T>(query, args).SingleOrDefault();
}
static Type GetSomeType()
{
    return typeof(SomeType);
}
public class SomeType
{
    public int A { get;set; }
    public string B { get;set; }
}

注意,这只是从一个Type开始,并通过一个虚拟实例(通过Activator)和dynamic填充一个实例。不是很漂亮,但很有效。但是,我也刚刚对dapper进行了一些更改,使其接受Type实例作为参数,从而使以下内容也可以工作,而不需要这些hack:

public void TypeBasedViaType()
{
    Type type = GetSomeType();
    dynamic actual = connection.Query(type,
        "select @A as [A], @B as [B]", new { A = 123, B = "abc" }
        ).FirstOrDefault();
    ((object)actual).GetType().IsEqualTo(type);
    int a = actual.A;
    string b = actual.B;
    a.IsEqualTo(123);
    b.IsEqualTo("abc");
}

和多网格阅读器:

public void TypeBasedViaTypeMulti()
{
    Type type = GetSomeType();
    dynamic first, second;
    using(var multi = connection.QueryMultiple(
        "select @A as [A], @B as [B]; select @C as [A], @D as [B]",
        new { A = 123, B = "abc", C = 456, D = "def" }))
    {
        first = multi.Read(type).Single();
        second = multi.Read(type).Single();
    }
    ((object)first).GetType().IsEqualTo(type);
    int a = first.A;
    string b = first.B;
    a.IsEqualTo(123);
    b.IsEqualTo("abc");
    ((object)second).GetType().IsEqualTo(type);
    a = second.A;
    b = second.B;
    a.IsEqualTo(456);
    b.IsEqualTo("def");
}

请注意,这些新API示例中的dynamic纯粹是为了方便测试;dynamic不是该方法的重要组成部分。

相关内容

  • 没有找到相关文章

最新更新