¿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?



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

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;
}

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 ....
}

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;
    }

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;
           }

       }

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.


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;
}

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")){
    // ...
}

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;
    }

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;
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.