如何创建一个动态确定的属性名称的匿名对象?
给定一个值数组,我想创建一个具有基于这些值的属性的匿名对象。 属性名称只是"pN"
,其中N
是数组中值的索引。
例如,给定
object[] values = { 123, "foo" };
我想创建一个匿名对象
new { p0 = 123, p1 = "foo" };
我能想到的唯一方法就是使用一个switch
或链接到合理数量的参数来支持,但我想知道是否有更优雅的方法来做到这一点:
object[] parameterValues = new object[] { 123, "foo" }; dynamic values = null; switch (parameterValues.Length) { case 1: values = new { p0 = parameterValues[0] }; break; case 2: values = new { p0 = parameterValues[0], p1 = parameterValues[1] }; break; // etc. up to a reasonable # of parameters }
背景
我有一组现有的方法来对数据库执行sql语句。 这些方法通常采用sql语句的string
和params object[]
(如果有的话)。 理解是如果查询使用参数,它们将被命名为@p0, @p1, @p2, etc.
。
例:
public int ExecuteNonQuery(string commandText, CommandType commandType, params object[] parameterValues) { .... }
这将被称为:
db.ExecuteNonQuery("insert into MyTable(Col1, Col2) values (@p0, @p1)", CommandType.Text, 123, "foo");
现在我想在这个类中使用Dapper来包装和公开Dapper的Query
方法,并以与现有方法一致的方式进行,例如:
public IEnumerable ExecuteQuery(string commandText, CommandType commandType, params object[] parameterValues) { .... }
但Dapper的Query
方法获取匿名对象中的参数值:
var dog = connection.Query("select Age = @Age, Id = @Id", new { Age = (int?)null, Id = guid });
导致我关于创建匿名对象以将参数传递给Dapper的问题。
使用@Paolo Tedesco请求的DynamicParameter类添加代码。
string sql = "select * from Account where Id = @p0 and username = @p1"; dynamic values = new DynamicParameter(123, "test"); var accounts = SqlMapper.Query(connection, sql, values);
在Dapper的SqlMapper.cs文件的第581行引发exception:
using (var reader = cmd.ExecuteReader())
并且exception是SqlException
:
必须声明标量变量“@ p0”。
并检查cmd.Parameters
属性显示没有为该命令配置参数。
你滥用Dapper,你永远不需要这样做,而是实现IDynamicParameters
或使用特定的极其灵活的DynamicParameters
类。
特别是:
string sql = "select * from Account where Id = @id and username = @name"; var values = new DynamicParameters(); values.Add("id", 1); values.Add("name", "bob"); var accounts = SqlMapper.Query(connection, sql, values);
DynamicParameters
可以在构造函数中接受匿名类。 您可以使用AddDynamicParams
方法连接AddDynamicParams
。
此外,对匿名类型没有严格的依赖性。 Dapper将允许混凝土类型作为参数,例如:
class Stuff { public int Thing { get; set; } } ... cnn.Execute("select @Thing", new Stuff{Thing = 1});
凯文有一个类似的问题: 寻找一种快速简便的方法来合并POCO上的所有属性 – DynamicParameters
在这里完美运行,而不需要魔术箍跳跃。
不完全是一个匿名对象,但是如何实现一个DynamicObject ,它根据数组中的值返回p1 … pn的值? 这会与Dapper一起工作吗?
例:
using System; using System.Dynamic; using System.Text.RegularExpressions; class DynamicParameter : DynamicObject { object[] _p; public DynamicParameter(params object[] p) { _p = p; } public override bool TryGetMember(GetMemberBinder binder, out object result) { Match m = Regex.Match(binder.Name, @"^p(\d+)$"); if (m.Success) { int index = int.Parse(m.Groups[1].Value); if (index < _p.Length) { result = _p[index]; return true; } } return base.TryGetMember(binder, out result); } } class Program { static void Main(string[] args) { dynamic d1 = new DynamicParameter(123, "test"); Console.WriteLine(d1.p0); Console.WriteLine(d1.p1); } }
您无法动态创建匿名对象。 但是Dapper应该使用动态对象。 要以一种很好的方式创建动态对象,可以使用Clay 。 它使您能够编写类似的代码
var person = New.Person(); person["FirstName"] = "Louis"; // person.FirstName now returns "Louis"