gpt4 book ai didi

c# - 动态 List.Add 抛出 RuntimeBinderException

转载 作者:行者123 更新时间:2023-12-02 01:02:21 25 4
gpt4 key购买 nike

我正在为 OrientDB .Net 库编写一些扩展方法,在 C# 中的模型类和数据库中的图形之间进行映射(反之亦然)。这必然需要一些反射(reflection)和动态规划。

以下方法用于设置表示顶点之间边的模型对象的属性值。例如,如果顶点 A 通过边 C 链接到多个顶点 B,则模型 A 可能具有类型为 List<B> 的属性。而模型 B 将具有 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);
}
}

模型中的属性可以具有为它们提供别名的属性,以帮助在数据库和 C# 类之间进行映射,因此 IsModelPropertyIsModelCollectionProperty检查该别名以及属性类型是否为可枚举类型。

但是,当我运行我的代码时,我得到一个 RuntimeBinderExceptionpropertyValue.Add(child) 行:

An unhandled exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in OrientTest.exe

Additional information: The best overloaded method match for 'System.Collections.Generic.List.Add(OrientTest.Participant)' has some invalid arguments

异常点:

  • parentOrientTest.Employer 的实例
  • childOrientTest.Participant 的实例
  • className是“EmployerParticipant”(在数据库中将 Employer 和 Participant 顶点连接在一起的边类的名称)
  • properties包含 7 个元素,每个元素对应于 Employer 中的一个属性
  • propertySinglenull
  • propertyCollection代表属性(property) List<Participant> Participants
  • propertyValueList<Participant> 的实例

我不明白为什么List<Participant>#Add(Participant)参数无效,但是 dynamic经常做奇怪的事情。

最佳答案

重载解析失败,因为 child 的类型是ABaseModel , 不是 OrientTest.Participant .它在运行时的值恰好是方法期望的类型并不重要。鉴于名称 RuntimeBinder,这似乎违反直觉,但其中有道理:重载决议的规则虽然在运行时应用,但与 C# 在编译时使用的规则相同(因为 dynamic 实际上是一个普通的旧 C# 对象)。偏离这一点会导致更多的惊喜。

如果您自己编写 DynamicObject,当然可以覆盖或规避此行为实现,所以这不是 dynamic 的一般限制-- 这只是意味着你不能(滥用)使用 dynamic以这种方式在运行时进行方法解析。

在这种情况下,如果您知道该属性始终属于 List<T> 类型,则有一个简单的修复方法对于一些 T ,因为 List<T>工具 IList它接受任何旧的 object (可能有运行时异常):

IList propertyValue = (IList) propertyCollection.GetValue(parent);
...
propertyValue.Add(child);

如果您不知道它是一个列表,您将不得不硬着头皮调用 Add动态方法:

object propertyValue = propertyCollection.GetValue(parent);
...
propertyValue.GetType().GetMethod("Add").Invoke(propertyValue, child);

如果对象有多个 .Add(),这又会失败您要使用“最正确”的方法。我假设我们不需要涵盖该特定案例。

实际上还有第三种方法,它在这里有点矫枉过正,但在其他情况下可能会有用,那就是使论证本身成为 dynamic所以分辨率被迫在运行时做“正确的事情”(对于“正确”的某些值):

propertyValue.Add((dynamic) child);

关于c# - 动态 List<T>.Add 抛出 RuntimeBinderException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27157921/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com