As I've mentioned in my comment, you're asking two separate questions, which are only loosely related, but I'd do my best to explain the distinction and to answer them both:
Question #1: How would you use HasValue
for nullable properties on dynamic objects?
The short answer is; you can't, without unboxing. As an example, you could unbox the Guid
property in your code as follows:
((Guid?)person.Guid).HasValue
The reason behind this can be explained by examining some of the characteristics of dynamic
and Nullable
:
dynamic
is a compile-time concept and doesn't exist at runtime. So under the hood, it's just an object
.
- When using a
dynamic
variable, any child property and\or method is inherently dynamic
as well.
- A
Nullable<>
doesn't get boxed as-is. Instead, you'd get either a null object reference if it's null
or you'd get the underlying type (e.g. System.Guid
).
What this means for your example is that person
gets boxed as well as the Guid
property. Since the Guid
property is nullable, it gets boxed as a either System.Guid
(if it's not null
) or null
, eliminating the nullability of that property (which could lead to several different runtime exceptions).
Another, perhaps simpler solution, would be to just compare it with null
. For example:
person.Guid != null
Question #2: How would you convert an entire object graph to ExpandoObject
?
Contrary to the previous question, the solution to this question is perhaps easier to grasp (while it could require more code to implement).
To recursively convert an entire object graph to ExpandoObject
you could simply make your function recursive. For example:
public ExpandoObject ToExpando(object @object)
{
var properties = @object.GetType().GetProperties();
IDictionary<string, object> expando = new ExpandoObject();
foreach (var property in properties)
{
var value = GetValueOrExpandoObject(@object, property);
expando.Add(property.Name, value);
}
return (ExpandoObject)expando;
}
public object GetValueOrExpandoObject(object @object, PropertyInfo property)
{
var value = property.GetValue(@object);
if (value == null) return null;
var valueType = value.GetType();
if (valueType.IsValueType || value is string) return value;
if (value is IEnumerable enumerable) return ToExpandoCollection(enumerable);
return ToExpando(value);
}
public IEnumerable<ExpandoObject> ToExpandoCollection(IEnumerable enumerable)
{
var enumerator = enumerable.GetEnumerator();
while (enumerator.MoveNext())
{
yield return ToExpando(enumerator.Current);
}
}
In this example, I'm (naively) checking for each property whether or not the value should be converted to ExpandoObject
(e.g. if it's a value type) and if it is, call ToExpando
with the property's value.
Please note that this is far from the ideal solution, but it shows how quickly this can get out of control. The more types you need to handle differently the more complex this would get, so if you end up implementing something like this, you should consider the visitor pattern.
Lastly, I'd like to note that I would in general strongly recommend you avoid using dynamic
completely if at all possible since it is very expensive both from a technical standpoint and from a cognitive one (i.e. understanding what the code does and what could go wrong).