I need to loop over a List<dynamic>
objects.
The list's objects all have values, but for some reason, I am not able to access any of the dynamic object fields. Below is a screenshot of my debug window:
There you can see the object contains fields (such Alias, Id, Name, etc).
I tried both casting it to a IDictionary<string, object>
and ExpandoObject
, to no avail. I did not face such a thing before: failing to access existing fields in a dynamic
object when they exist.
What is wrong here?
The code is throwing a Microsoft.CSharp.RuntimeBinder.RuntimeBinderException
with a message stating {"'object' does not contain a definition for 'Name'"}.
The list was created adding anonymously-typed objects, like this:
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
}));
where fields
is an ICollection<Field>
, a strongly-typed collection.
The telling part is the exception:
This indicates that the runtime binder was not actually capable of accessing the type you're passing in
dynamic
(sincedynamic
does actually enforce visibility rules).The most likely cause of this is that you're creating the anonymous type in a different assembly from the one where you're subsequently reading it - since anonymous types are declared
internal
, the consuming assembly cannot access it, causing the error message above.Contrast with the usual case of runtime binder exceptions:
EDIT:
A possible solution to the problem is to use the
InternalsVisibleToAttribute
on the assembly containing the anonymous type. However, this is code smell - just like any other use ofInternalsVisibleToAttribute
orinternal
itself.A better way would be to make sure you don't actually pass anonymous types over assembly boundaries - after all, they shouldn't even be used outside of the method they originated from; the fact that they are is basically an implementation detail of .NET - they didn't have another way to do the same thing. This could change in future versions, making the
InternalsVisibleToAttribute
solution doubly unreliable.The way your code is using
dynamic
suggests that your team has flawed assumptions about howdynamic
works and how it's supposed to be used. Note how the actual runtime type ofList<dynamic>
is actuallyList<object>
. The same goes for arguments of typedynamic
(which are again justobject
, albeit marked withDynamicAttribute
). And in fact, that really is whatdynamic
is - it's a way to handle runtime dynamic dispatch - it's not a property of the type or anything, it's just the way you actually invoke whatever you're trying to invoke. For C#,dynamic
allows you to skip most of the compiler checks when working with those dynamic types, and it generates some code to handle the dispatch for you automatically, but all of that only happens inside the method where you actually use thedynamic
keyword - if you usedList<object>
, the end result would be exactly the same.In your code, there's no reason not to use simple static types. Dynamic typing doesn't really give you any benefits, apart from the effort to code the types themselves. If your co-workers don't like that, well, they should present a better solution - the problem is quite obvious, and it's something you need to deal with.
Much worse, it explicitly hides all context, all the type information. That's not something you want in an API, internal or not! If you want to hide the concrete types being used, why not - but you should still expose an interface instead. I suspect this is the reason why anonymous types can't implement interfaces - it would encourage you to go entirely the wrong way.