List<dynamic> 元素有字段,但我无法访问它们。为什么?
List<dynamic> elements have fields but I cannot access them. Why?
我需要遍历 List<dynamic>
个对象。
列表的对象都有值,但由于某种原因,我无法访问任何动态对象字段。下面是我调试的截图 window:
在那里您可以看到对象包含字段(例如 Alias、Id、Name等)。
我尝试将其转换为 IDictionary<string, object>
和 ExpandoObject
,但无济于事。我以前没有遇到过这样的事情:无法访问 dynamic
对象中的现有字段 当它们存在时 .
这里有什么问题?
代码正在抛出一个 Microsoft.CSharp.RuntimeBinder.RuntimeBinderException
并显示一条消息 {"'object' does not contain a definition for 'Name'"}.
创建列表时添加了匿名类型的对象,如下所示:
return new List<dynamic>(fields.Select(field => new
{
Id = field.Id,
Alias = field.Alias,
Name = field.Name,
Type = field.Type,
Value = field.Value,
SortOrder = field.SortOrder
}));
其中 fields
是一个 ICollection<Field>
,一个强类型集合。
说明部分是例外:
{"'object' does not contain a definition for 'Name'"}.
这表明运行时绑定器实际上无法访问您在 dynamic
中传递的类型(因为 dynamic
实际上执行可见性规则)。
最可能的原因是您在与您随后阅读它的程序集不同的程序集中创建匿名类型 - 因为声明了匿名类型 internal
,消费程序集不能访问它,导致上面的错误消息。
与运行时活页夹异常的常见情况对比:
'<>f__AnonymousType0< string >' does not contain a definition for 'Name'
编辑:
该问题的一个可能解决方案是对包含匿名类型的程序集使用 InternalsVisibleToAttribute
。然而,这是代码味道 - 就像 InternalsVisibleToAttribute
或 internal
本身的任何其他使用一样。
更好的方法是确保您实际上没有在程序集边界上传递匿名类型——毕竟,它们甚至不应该在它们起源的方法之外使用;事实上,它们基本上是 .NET 的一个实现细节——它们没有另一种方法来做同样的事情。这 可能会 在未来的版本中发生变化,使 InternalsVisibleToAttribute
解决方案更加不可靠。
您的代码使用 dynamic
的方式表明您的团队对 dynamic
的工作方式和使用方式有错误的假设。请注意 List<dynamic>
的实际运行时类型实际上是 List<object>
。 dynamic
类型的参数也是如此(同样只是 object
,尽管标记为 DynamicAttribute
)。事实上,这确实是 dynamic
是什么 - 它是一种处理运行时动态调度的方法 - 它不是类型的 属性 或任何东西,它只是您实际 调用 的方式,无论您尝试调用什么。对于 C#,dynamic
允许您在使用这些动态类型时跳过大部分编译器检查,并且它会生成一些代码来自动为您处理分派,但所有这些只发生在您实际使用的方法内部dynamic
关键字 - 如果您使用 List<object>
,最终结果将完全相同。
在您的代码中,没有理由不使用简单的静态类型。除了为类型本身编写代码之外,动态类型并没有真正给您带来任何好处。如果您的同事不喜欢那样,那么,他们应该提出一个更好的解决方案 - 这个问题很明显,这是您 需要 处理的问题。
更糟糕的是,它明确地隐藏了所有上下文、所有类型信息。在 API 中,无论内部与否,这都不是您想要的!如果你想隐藏正在使用的具体类型,为什么不呢——但你仍然应该公开一个接口。我怀疑这就是匿名类型不能实现接口的原因——它会鼓励你走完全错误的道路。
我需要遍历 List<dynamic>
个对象。
列表的对象都有值,但由于某种原因,我无法访问任何动态对象字段。下面是我调试的截图 window:
在那里您可以看到对象包含字段(例如 Alias、Id、Name等)。
我尝试将其转换为 IDictionary<string, object>
和 ExpandoObject
,但无济于事。我以前没有遇到过这样的事情:无法访问 dynamic
对象中的现有字段 当它们存在时 .
这里有什么问题?
代码正在抛出一个 Microsoft.CSharp.RuntimeBinder.RuntimeBinderException
并显示一条消息 {"'object' does not contain a definition for 'Name'"}.
创建列表时添加了匿名类型的对象,如下所示:
return new List<dynamic>(fields.Select(field => new
{
Id = field.Id,
Alias = field.Alias,
Name = field.Name,
Type = field.Type,
Value = field.Value,
SortOrder = field.SortOrder
}));
其中 fields
是一个 ICollection<Field>
,一个强类型集合。
说明部分是例外:
{"'object' does not contain a definition for 'Name'"}.
这表明运行时绑定器实际上无法访问您在 dynamic
中传递的类型(因为 dynamic
实际上执行可见性规则)。
最可能的原因是您在与您随后阅读它的程序集不同的程序集中创建匿名类型 - 因为声明了匿名类型 internal
,消费程序集不能访问它,导致上面的错误消息。
与运行时活页夹异常的常见情况对比:
'<>f__AnonymousType0< string >' does not contain a definition for 'Name'
编辑:
该问题的一个可能解决方案是对包含匿名类型的程序集使用 InternalsVisibleToAttribute
。然而,这是代码味道 - 就像 InternalsVisibleToAttribute
或 internal
本身的任何其他使用一样。
更好的方法是确保您实际上没有在程序集边界上传递匿名类型——毕竟,它们甚至不应该在它们起源的方法之外使用;事实上,它们基本上是 .NET 的一个实现细节——它们没有另一种方法来做同样的事情。这 可能会 在未来的版本中发生变化,使 InternalsVisibleToAttribute
解决方案更加不可靠。
您的代码使用 dynamic
的方式表明您的团队对 dynamic
的工作方式和使用方式有错误的假设。请注意 List<dynamic>
的实际运行时类型实际上是 List<object>
。 dynamic
类型的参数也是如此(同样只是 object
,尽管标记为 DynamicAttribute
)。事实上,这确实是 dynamic
是什么 - 它是一种处理运行时动态调度的方法 - 它不是类型的 属性 或任何东西,它只是您实际 调用 的方式,无论您尝试调用什么。对于 C#,dynamic
允许您在使用这些动态类型时跳过大部分编译器检查,并且它会生成一些代码来自动为您处理分派,但所有这些只发生在您实际使用的方法内部dynamic
关键字 - 如果您使用 List<object>
,最终结果将完全相同。
在您的代码中,没有理由不使用简单的静态类型。除了为类型本身编写代码之外,动态类型并没有真正给您带来任何好处。如果您的同事不喜欢那样,那么,他们应该提出一个更好的解决方案 - 这个问题很明显,这是您 需要 处理的问题。
更糟糕的是,它明确地隐藏了所有上下文、所有类型信息。在 API 中,无论内部与否,这都不是您想要的!如果你想隐藏正在使用的具体类型,为什么不呢——但你仍然应该公开一个接口。我怀疑这就是匿名类型不能实现接口的原因——它会鼓励你走完全错误的道路。