dynamically - expandoobject c# example
¿Hay alguna manera de realizar una comprobación nula encadenada en una dinámica/expansión? (2)
C # tiene el útil operador condicional nulo . Bien explicado en esta respuesta también.
Me preguntaba si es posible hacer un control similar como este cuando mi objeto es un objeto dinámico / expando. Déjame mostrarte un código:
Dada esta jerarquía de clase
public class ClsLevel1
{
public ClsLevel2 ClsLevel2 { get; set; }
public ClsLevel1()
{
this.ClsLevel2 = new ClsLevel2(); // You can comment this line to test
}
}
public class ClsLevel2
{
public ClsLevel3 ClsLevel3 { get; set; }
public ClsLevel2()
{
this.ClsLevel3 = new ClsLevel3();
}
}
public class ClsLevel3
{
// No child
public ClsLevel3()
{
}
}
Si realizo este tipo de verificación nula encadenada, funciona
ClsLevel1 levelRoot = new ClsLevel1();
if (levelRoot?.ClsLevel2?.ClsLevel3 != null)
{
// will enter here if you DO NOT comment the content of the ClsLevel1 constructor
}
else
{
// will enter here if you COMMENT the content of the ClsLevel1
}
Ahora, intentaré reproducir este comportamiento con dinámica (ExpandoObjects)
dynamic dinRoot = new ExpandoObject();
dynamic DinLevel1 = new ExpandoObject();
dynamic DinLevel2 = new ExpandoObject();
dynamic DinLevel3 = new ExpandoObject();
dinRoot.DinLevel1 = DinLevel1;
dinRoot.DinLevel1.DinLevel2 = DinLevel2;
//dinRoot.DinLevel1.DinLevel2.DinLevel3 = DinLevel3; // You can comment this line to test
if (dinRoot?.DinLevel1?.DinLevel2?.DinLevel3 != null)
{
// Obviously it will raise an exception because the DinLevel3 does not exists, it is commented right now.
}
¿Hay alguna manera de simular este comportamiento con la dinámica? Quiero decir, verificar un nulo en una larga cadena de miembros.
EDITAR: corregido, ya que ExpandoObjects y los métodos de extensión no funcionan bien juntos. Un poco menos agradable, pero con suerte aún usable.
Método (s) de ayuda:
public static class DynamicExtensions
{
public static Object TryGetProperty(ExpandoObject obj, String name)
{
return name.Split(''.'')
.Aggregate((Object)obj, (o, s) => o != null
? TryGetPropertyInternal(o, s)
: null);
}
private static Object TryGetPropertyInternal(Object obj, String name)
{
var dict = obj as IDictionary<String, Object>;
return (dict?.ContainsKey(name) ?? false) ? dict[name] : null;
}
}
Uso:
if (DynamicExtensions.TryGetProperty(dinRoot, "DinLevel1.DinLevel2.DinLevel3") != null)
Si desea admitir esto de forma más natural, puede heredar de DynamicObject y proporcionar una implementación personalizada:
class MyExpando : DynamicObject
{
private readonly Dictionary<string, object> _dictionary = new Dictionary<string, object>();
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
var name = binder.Name.ToLower();
result = _dictionary.ContainsKey(name) ? _dictionary[name] : null;
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
_dictionary[binder.Name.ToLower()] = value;
return true;
}
}
Pruebas:
private static void Main(string[] args)
{
dynamic foo = new MyExpando();
if (foo.Boo?.Lol ?? true)
{
Console.WriteLine("It works!");
}
Console.ReadLine();
}
La salida será "¡Funciona!". Como Boo no existe, obtenemos una referencia nula para que el operador condicional nulo pueda funcionar.
Lo que hacemos aquí es devolver una referencia nula al parámetro de salida de TryGetMember cada vez que no se encuentra una propiedad y siempre devolvemos la verdad.
Espero que esto ayude