Bri*_*n S 2 c# reflection dynamic
我正在为 OrientDB .Net 库编写一些扩展方法,在 C# 中的模型类和数据库中的图形之间进行映射(反之亦然)。这必然需要一些反射和动态编程。
以下方法用于设置表示顶点之间边的模型对象上的属性值。例如,如果顶点 A 通过边 C 链接到多个顶点 B,则模型 A 可能具有 type 属性,List<B>而模型 B 将具有 type 属性A(对于一对多关系)。
private static void SetLinkedProperty(
ABaseModel parent, ABaseModel child, string className)
{
PropertyInfo[] properties = parent.GetType()
.GetProperties(BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.SetProperty |
BindingFlags.GetProperty);
PropertyInfo propertySingle = properties
.Where(prop => IsModelProperty(prop, className)).SingleOrDefault();
PropertyInfo propertyCollection = properties
.Where(prop => IsModelCollectionProperty(prop, className)).SingleOrDefault();
if (propertySingle != null)
{
propertySingle.SetValue(parent, child);
}
if (propertyCollection != null)
{
dynamic propertyValue = propertyCollection.GetValue(parent);
if (propertyValue == null)
{
Type listOfT = typeof(List<>).MakeGenericType(
propertyCollection.PropertyType.GenericTypeArguments[0]);
IEnumerable collection = (IEnumerable)Activator.CreateInstance(listOfT);
propertyValue = collection;
propertyCollection.SetValue(parent, collection);
}
propertyValue.Add(child);
}
}
Run Code Online (Sandbox Code Playgroud)
模型中的属性可以具有为它们提供别名的属性,以帮助在 DB 和 C# 类之间进行映射,因此IsModelProperty并IsModelCollectionProperty检查该别名以及属性类型是否为可枚举类型。
然而,当我运行我的代码时,我得到了RuntimeBinderException一行propertyValue.Add(child):
OrientTest.exe 中发生类型为“Microsoft.CSharp.RuntimeBinder.RuntimeBinderException”的未处理异常
附加信息:“System.Collections.Generic.List.Add(OrientTest.Participant)”的最佳重载方法匹配有一些无效参数
在异常点:
parent 是一个实例 OrientTest.Employerchild 是一个实例 OrientTest.ParticipantclassName 是“EmployerParticipant”(在数据库中将 Employer 和 Participant 顶点链接在一起的边类的名称)properties 包含 7 个元素,每个元素对应于 EmployerpropertySingle 是 nullpropertyCollection 代表财产 List<Participant> ParticipantspropertyValue 是一个实例 List<Participant>我不明白为什么List<Participant>#Add(Participant)有无效的论点,但dynamic经常做奇怪的事情。
重载解析失败,因为类型child是ABaseModel,不是OrientTest.Participant。它在运行时的值恰好是方法期望的类型并不重要。考虑到名称RuntimeBinder,这似乎违反直觉,但它是有道理的:重载解析规则虽然在运行时应用,但与 C# 在编译时使用的规则相同(因为dynamic它实际上是一个普通的旧 C# 对象)。偏离这一点会导致更多的惊喜。
当然,如果您编写自己的DynamicObject实现,您可以覆盖或规避此行为,因此这不是一般限制dynamic——它只是意味着您不能(ab)使用dynamic这种方式在运行时进行方法解析。
在这种情况下,如果您知道属性始终是List<T>some的类型,则有一个简单的修复方法T,因为List<T>implementsIList接受任何旧的object(带有可能的运行时异常):
IList propertyValue = (IList) propertyCollection.GetValue(parent);
...
propertyValue.Add(child);
Run Code Online (Sandbox Code Playgroud)
如果您不知道这是一个列表,则必须硬着头皮Add动态调用该方法:
object propertyValue = propertyCollection.GetValue(parent);
...
propertyValue.GetType().GetMethod("Add").Invoke(propertyValue, child);
Run Code Online (Sandbox Code Playgroud)
如果对象有多种.Add()方法,而您想要使用“最正确”的方法,这反过来会失败。我假设我们不需要涵盖那个特殊情况。
实际上还有第三种方法,这在这里有点矫枉过正,但在其他情况下可能很有用,那就是使参数本身dynamic成为强制解析在运行时做“正确的事情”(对于“正确”的某些值):
propertyValue.Add((dynamic) child);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1665 次 |
| 最近记录: |