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

时间:2014-07-06 04:36:29

标签: reflection types dapper

我试图在运行时动态传递类的类型。以下代码在代码部分给出错误:

    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(),以便通用形式的属性可以与结果集一起映射。如果我通过&#34; newObject&#34;或&#34; Type.GetType(t.GetGenericArguments()[0] .FullName)&#34;它仍然给我错误。这可能看起来很笨拙,但我认为它应该有用。

1 个答案:

答案 0 :(得分:2)

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

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填充实例。不漂亮,但它的工作原理。但是,我也只是将一些更改推送到接受Type实例作为参数的dapper,使得以下内容也起作用 - 无需这些黑客:

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不是该方法的重要组成部分。