【发布时间】:2016-09-13 09:58:27
【问题描述】:
我们正在使用 Dapper 从我们的 SQL 数据库中获取数据,该数据库将我们的数据作为“动态”集合返回。我了解动态类型的力量,以及“鸭子打字”的灵活性,基本上“如果它像鸭子一样嘎嘎叫,那么它就是鸭子——我不需要声明它是鸭子”。
但是,我不明白为什么如果我尝试从动态对象中获取它没有的属性,它为什么不抱怨?例如,如果我有一个不是鸭子的东西,我在上面叫了“嘎嘎”,我会认为期待它抱怨是合理的。编辑:见 cmets,这似乎与 Dapper 给我的动态有关,因为如果属性不存在,标准动态对象会给出运行时错误。
有什么方法可以让它抱怨吗?
我的代码是一系列行,从“动态”中获取属性并将它们分配给强类型对象中的相应属性。属性名称并不总是捆绑在一起(由于遗留数据库命名标准)。目前,如果动态上的字段名称拼写错误,那么它将默默地失败。我想让它抱怨。我不想将每一行代码重写为5行“动态上是否存在[硬编码名称]属性”/“如果不抱怨”/“获取值并将其放在正确的位置”。
编辑:这是具体的代码,以防万一......不正确的字段名称是“result.DecisionLevel”,我没有收到运行时错误,它只是将null分配给目标属性
var results = _connection.Query("usp_sel_Solution", new { IdCase = caseId }, commandType: CommandType.StoredProcedure);
return results.Select(result => new Solution
{
IsDeleted = result.IsDeleted,
FriendlyName = result.FriendlyName,
DecisionLevel = (DecisionLevel?)result.DecisionLevel,
}).ToList();
解决方案:this 接受的答案,加上 Sergey 的回答,让我得到了这个解决方案:
internal class SafeDynamic : DynamicObject
{
private readonly IDictionary<string, object> _source;
public SafeDynamic(dynamic source)
{
_source = source as IDictionary<string, object>;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (_source.TryGetValue(binder.Name, out result) == false)
{
throw new NotSupportedException(binder.Name);
}
return true;
}
// I'll refactor this later, probably to an extension method...
public static IEnumerable<dynamic> Create(IEnumerable<dynamic> rows)
{
return rows.Select(x => new SafeDynamic(x));
}
}
对示例代码的唯一更改是包装对 Dapper 的 Query 方法的调用:
var results = SafeDynamic.Create(_connection.Query("usp_sel_Solution", new { IdCase = caseId }, commandType: CommandType.StoredProcedure));
谢谢。
为了后代,我将添加指向我为 how to do the same thing for Query<T> 提供的解决方案的链接,并注意编辑 25/1/17 “改进以避免静态字典上的线程问题”,这也适用于解决方案显示在这里。
【问题讨论】:
-
使用
dynamic,您可以绕过所有此类编译器类型检查。因此,您会在运行时而不是在编译时收到错误。 -
我的单元测试表明你没有。它只是没有给目标值赋值。
-
添加一些与帖子相关的好标签是一个很好的做法,这样很多人可以到达您的问题,并且您可能很快就会得到答案。
-
我不理解您的评论。你不是什么?第二点:如果你写
myDuck.woof它显然不会为你的鸭子分配任何东西,但是在编译时你会得到一个错误 if myDuck* is strong typed as aDuck,而使用dynamic,您会完全丢失该检查,使其默默地忽略无效调用。 -
我的单元测试表明您在运行时没有收到错误。它只是没有给目标值赋值