¿Cómo verifico si existe una propiedad en un tipo anónimo dinámico en c #?

122

Tengo un objeto de tipo anónimo que recibo como dinámico de un método que me gustaría comprobar si existe una propiedad en ese objeto.

....
var settings = new {
                   Filename="temp.txt",
                   Size=10
}
...

function void Settings(dynamic settings) {
var exists = IsSettingExist(settings,"Filename")
}

¿Cómo implementaría IsSettingExist?

David MZ
fuente
Si te encuentras confiando mucho en objetos dinámicos, probablemente valga la pena mirar F # - Nice Avatar por cierto
Piotr Kula

Respuestas:

149
  public static bool IsPropertyExist(dynamic settings, string name)
  {
    if (settings is ExpandoObject)
      return ((IDictionary<string, object>)settings).ContainsKey(name);

    return settings.GetType().GetProperty(name) != null;
  }

  var settings = new {Filename = @"c:\temp\q.txt"};
  Console.WriteLine(IsPropertyExist(settings, "Filename"));
  Console.WriteLine(IsPropertyExist(settings, "Size"));

Salida:

 True
 False
Serj-Tm
fuente
3
Esto no funciona en objetos dinámicos. Siempre devuelve nulo.
evilom
@evilom @Shikasta_Kashti ¿Estás intentando usar este método con un MVC ViewBag? Si es así, consulte stackoverflow.com/a/24192518/70345
Ian Kemp
@ Gaspa79. Es una convención de codificación bastante común. A algunas personas les gusta un prefijo "Es" en todas las propiedades booleanas. Una consistencia como esa puede evitar que tenga que adivinar los primeros caracteres de un identificador (después de lo cual, Intellisense funciona), pero a expensas de hacer un inglés un poco incómodo en casos como este.
solublefish
Encuentro que el tiempo verbal inválido del Isprefijo es más confuso de lo que sería de otra manera HasProperty. También diría que usar un prefijo gramaticalmente incorrecto como este en realidad no es idiomático en C♯.
Ben Collins
ExpandoObject no es lo mismo que el tipo anónimo. ¿Me equivoco en eso?
ryanwebjackson hace
37
public static bool HasProperty(dynamic obj, string name)
{
    Type objType = obj.GetType();

    if (objType == typeof(ExpandoObject))
    {
        return ((IDictionary<string, object>)obj).ContainsKey(name);
    }

    return objType.GetProperty(name) != null;
}
Sergey
fuente
objType.GetProperty(name) != null;devuelve nulo en propiedades que existen
Matas Vaitkevicius
3
objType.GetProperty(name) != nullsiempre devolverá a bool, que (por definición) nunca puede ser null.
Alex McMillan
@AlexMcMillan No estoy seguro de en qué dimensión vive donde Type.GetProperty(string)una propiedad inexistente devuelve algo que no sea nulo.
Ian Kemp
2
@IanKemp, AlexMcMillan dijo objType.GetProperty (name)! = Null en respuesta al comentario de MatasVaitkevicius en realidad.
Sergey
15

si puede controlar la creación / transmisión del objeto de configuración, le recomendaría usar un ExpandoObject en su lugar.

dynamic settings = new ExpandoObject();
settings.Filename = "asdf.txt";
settings.Size = 10;
...

function void Settings(dynamic settings)
{
    if ( ((IDictionary<string, object>)settings).ContainsKey("Filename") )
        .... do something ....
}
Mike Corcoran
fuente
No puedo cambiarlo, ¿puedo enviar contenido a ExpendoObject?
David MZ
6

Esto funciona para tipos anónimos ExpandoObject, Nancy.DynamicDictionaryo cualquier otra cosa a la que se pueda enviar IDictionary<string, object>.

    public static bool PropertyExists(dynamic obj, string name) {
        if (obj == null) return false;
        if (obj is IDictionary<string, object> dict) {
            return dict.ContainsKey(name);
        }
        return obj.GetType().GetProperty(name) != null;
    }
Seth Reno
fuente
2
Gran solucion Necesitaba agregar una declaración IF más al convertir una cadena JSON en JObject .... "if (obj es Newtonsoft.Json.Linq.JObject) return ((Newtonsoft.Json.Linq.JObject) obj) .ContainsKey (name); "
rr789
1
También funcionó para mí. Maravillosa respuesta Seth Reno. También he añadido "if (obj es Newtonsoft.Json.Linq.JObject) return ((Newtonsoft.Json.Linq.JObject) obj) .ContainsKey (name);" en la función anterior según lo sugerido por rr789. Así que edite también su respuesta para incluirla.
Brijesh Kumar Tripathi
1
¡Gracias @BrijeshKumarTripathi! Este era exactamente mi escenario.
ryanwebjackson hace
4

Esto es trabajo para mí-:

  public static bool IsPropertyExist(dynamic dynamicObj, string property)
       {
           try
           {
               var value=dynamicObj[property].Value;
               return true;
           }
           catch (RuntimeBinderException)
           {

               return false;
           }

       }
usuario3359453
fuente
14
Permitir que ocurran excepciones y luego atraparlas no es una solución preferida porque hay muchos gastos generales asociados con lanzar y atrapar. Es solo un último recurso. Las excepciones están diseñadas para situaciones que no deberían ocurrir en el curso de la ejecución, como una red que no está disponible. Aquí hay soluciones mucho mejores.
Whatever Man
Falla con RuntimeBinderExceptiony dynamicObj[property].Value cuando el valor es realmente allí ... var value = dynamicObj[property]es suficiente ... y cuando no existe KeyNotFoundException en Dictionaryse lanza ... ver más adelante ...
Matas Vaitkevicius
No es una solución aceptable utilizar excepciones en la lógica empresarial. 1º curso, 2º cuatrimestre.
Artem G
3

Ninguna de las soluciones anteriores funcionó para dynamiceso Json, sin embargo, logré transformar una con Try catch(por @ user3359453) cambiando el tipo de excepción lanzada (en KeyNotFoundExceptionlugar de RuntimeBinderException) en algo que realmente funciona ...

public static bool HasProperty(dynamic obj, string name)
    {
        try
        {
            var value = obj[name];
            return true;
        }
        catch (KeyNotFoundException)
        {
            return false;
        }
    }

ingrese la descripción de la imagen aquí

Espero que esto te ahorre algo de tiempo.

Matas Vaitkevicius
fuente
1
No se recomienda usar excepciones para cosas como estas. Debería haber optado por algo como convertir a JObject y usar .Property ()! =
Null
3

Fusionar y corregir respuestas de Serj-TM y user3359453 para que funcione con ExpandoObject y DynamicJsonObject. Esto funciona para mi.

public static bool HasPropertyExist(dynamic settings, string name)
{
    if (settings is System.Dynamic.ExpandoObject)
        return ((IDictionary<string, object>)settings).ContainsKey(name);

    if (settings is System.Web.Helpers.DynamicJsonObject)
    try
    {
        return settings[name] != null;
    }
    catch (KeyNotFoundException)
    {
        return false;
    }


    return settings.GetType().GetProperty(name) != null;
}
Bruno Marotta
fuente
2

Usando la reflexión, esta es la función que uso:

public static bool doesPropertyExist(dynamic obj, string property)
{
    return ((Type)obj.GetType()).GetProperties().Where(p => p.Name.Equals(property)).Any();
}

luego..

if (doesPropertyExist(myDynamicObject, "myProperty")){
    // ...
}
Chtiwi Malek
fuente
2
GetProperties () no enumera el miembro dinámico en un objeto dinámico. Hay una función dedicada GetDynamicMemberNames () para eso.
Marco Guignard
Usar la expresión lambda Whereprimero, y luego Anyes redundante, ya que también puede formular su expresión de filtrado Any.
pholpar
1

En caso de que alguien necesite manejar un objeto dinámico proveniente de Json, modifiqué la respuesta de Seth Reno para manejar el objeto dinámico deserializado de NewtonSoft.Json.JObjcet.

public static bool PropertyExists(dynamic obj, string name)
    {
        if (obj == null) return false;
        if (obj is ExpandoObject)
            return ((IDictionary<string, object>)obj).ContainsKey(name);
        if (obj is IDictionary<string, object> dict1)
            return dict1.ContainsKey(name);
        if (obj is IDictionary<string, JToken> dict2)
            return dict2.ContainsKey(name);
        return obj.GetType().GetProperty(name) != null;
    }
Kuroro
fuente
0

Para extender la respuesta de @Kuroro, si necesita probar si la propiedad está vacía, a continuación debería funcionar.

public static bool PropertyExistsAndIsNotNull(dynamic obj, string name)
{
    if (obj == null) return false;
    if (obj is ExpandoObject)
    {
        if (((IDictionary<string, object>)obj).ContainsKey(name))
            return ((IDictionary<string, object>)obj)[name] != null;
        return false;
    }
    if (obj is IDictionary<string, object> dict1)
    {
        if (dict1.ContainsKey(name))
            return dict1[name] != null;
        return false;
    }
    if (obj is IDictionary<string, JToken> dict2)
    {
        if (dict2.ContainsKey(name))
            return (dict2[name].Type != JTokenType.Null && dict2[name].Type != JTokenType.Undefined);
        return false;
    }
    if (obj.GetType().GetProperty(name) != null)
        return obj.GetType().GetProperty(name).GetValue(obj) != null;
    return false;
}
Mötz
fuente