如何使用Dapper泛型获取存储过程的所有输出参数
解决Dapper存储过程输出参数自动映射的问题
要实现不暴露Dapper类型的前提下自动映射输出参数,核心是通过反射调用DynamicParameters的泛型Get方法,绕过C#泛型参数必须为编译时常量的限制。以下是修改后的可行实现:
修改后的关键代码段
在执行存储过程后的赋值环节,替换你原来的两种尝试:
if (outputParameters != null) { var getMethod = typeof(DynamicParameters).GetMethod("Get", new Type[] { typeof(string) }); foreach (PropertyInfo prop in outputParameters.GetType().GetProperties()) { // 通过反射创建泛型版本的Get方法 var genericGetMethod = getMethod.MakeGenericMethod(prop.PropertyType); // 调用Get方法获取输出参数值 var value = genericGetMethod.Invoke(dynamicParameters, new object[] { prop.Name }); // 将值赋值给outputParameters的对应属性 prop.SetValue(outputParameters, value); } }
关键说明
- 反射调用泛型方法:通过
typeof(DynamicParameters).GetMethod获取Get<T>的非泛型方法定义,再用MakeGenericMethod传入属性的运行时类型,创建对应泛型版本的方法实例,最后用Invoke执行获取值。 - 参数名匹配:确保
Add参数时用的是属性名(prop.Name),获取时直接传相同的名称即可,无需额外加@,Dapper内部会自动处理SQL参数的命名规则。 - 类型映射正确性:你的
GetDbType方法必须正确将C#类型映射到对应的SQL DbType,否则输出参数可能无法正确赋值(比如字符串类型未指定长度、数值类型不匹配等)。
完整的CallProcedure方法示例
public void CallProcedure<I, O>( string storedProcedure, I inputParameters, O outputParameters, string connectionId = "Default") { using IDbConnection connection = new SqlConnection(_config.GetConnectionString(connectionId)); var dynamicParameters = new DynamicParameters(); if (inputParameters != null) dynamicParameters.AddDynamicParams(inputParameters); if (outputParameters != null) { foreach (PropertyInfo prop in outputParameters.GetType().GetProperties()) { dynamicParameters.Add( prop.Name, prop.GetValue(outputParameters), GetDbType(prop.PropertyType), ParameterDirection.Output); } } connection.Execute(storedProcedure, dynamicParameters, commandType: CommandType.StoredProcedure); if (outputParameters != null) { var getMethod = typeof(DynamicParameters).GetMethod("Get", new Type[] { typeof(string) }); foreach (PropertyInfo prop in outputParameters.GetType().GetProperties()) { var genericGetMethod = getMethod.MakeGenericMethod(prop.PropertyType); var value = genericGetMethod.Invoke(dynamicParameters, new object[] { prop.Name }); prop.SetValue(outputParameters, value); } } }
额外注意事项
- 确保
outputParameters的属性是可写的(即有set访问器),否则SetValue会失败。 - 如果存储过程的输出参数允许为
NULL,对应的C#属性应使用可空类型(如int?、string等),避免赋值时出现类型转换异常。
内容的提问来源于stack exchange,提问作者Monset
相关产品推荐
相关产品推荐

