Extensiones de lenguaje dinámico en C#

Extensiones de lenguaje dinámico en C#

dynamic elemento = new ExpandoObject();
elemento.PropiedadABC = "valor";
elemento.Numero = 10000;
Console.WriteLine(elemento.PropiedadABC);
elemento.PropiedadABC = "123";
Console.WriteLine(elemento.PropiedadABC);

El tipo dinámico dynamic permite lectura y escritura de valores. C# es un lenguaje compilado, mientras que JavaScript es interpretado. Por esta razón, en JavaScript podemos hacer referencia a una variable después de definirla. Sin embargo, con dynamic, una vez definido, no podemos hacer referencia directa a él ni conocer su tipo de forma anticipada. Solo en tiempo de ejecución se determina su tipo real.

Cuando no podemos determinar el tipo de un objeto dynamic, pueden surgir excepciones imprevistas como: excepciones de conversión, errores de serialización, acceso a propiedades inexistentes, entre otras. Por ello, al trabajar con dynamic es fundamental implementar manejo adecuado de excepciones.

En cuanto a la diferencia con var, el tipo var puede utilizarse inmediatamente después de su declaración. Una ventaja importante es que los miembros declarados con var son de solo lectura, aunque los valores de dichos miembros sí pueden modificarse.

dynamic elemento = new ExpandoObject();
elemento.PropiedadABC = "valor";
elemento.Numero = 10000;
Console.WriteLine(elemento.PropiedadABC);
elemento.PropiedadABC = "123";
Console.WriteLine(elemento.PropiedadABC);
            
Console.WriteLine(elemento.ToString());

var objetoAnonimo = new { PropiedadABC = "valor", Numero = 10000 };
Console.WriteLine(objetoAnonimo.ToString());

Para los tipos var, aunque los miembros son de solo lectura, los valores pueden modificarse si se trata de objetos anidados:

var objetoAnonimo = new { PropiedadABC = "valor", Numero = new { Elemento = new Persona() } };

Respecto a dynamic, після宣言後 se puede utilizar inmediatamente, sus miembros son de lectura y escritura, pero al no tener tipo definido, el desarrollador debe controlar completamente su procedencia y estructura.

La clase DynamicObject sirve como base para todos los tipos dinámicos personalizados. Se puede heredar de ella para implementar objetos con comportamiento dinámico personalizado. Por otro lado, ExpandoObject es una clase sellada que ya viene completamente implementada con toda la funcionalidad necesaria.

static void Main(string[] args)
 
        {
 
            dynamic objetoDinamico = new MiObjetoDinamico();
 
            objetoDinamico.Nombre = "Carlos";
 
            objetoDinamico.Apellido = "García";
 
            objetoDinamico.Edad = 35;
 
  
 
            Action<dynamic> mostrar = (elemento) => Console.WriteLine("Mi nombre es " + elemento.Nombre + " " + elemento.Apellido
 
                                                               + ". Tengo " + elemento.Edad + " años.");
 
            objetoDinamico.Mostrar = mostrar;
 
  
 
            objetoDinamico.Mostrar(objetoDinamico);
 
  
 
            Console.Read();
 
        }
 
  
 
 
public class MiObjetoDinamico : DynamicObject
 
    {
 
        private Dictionary<string, object> _almacenDinamico = new Dictionary<string, object>();
 
        public override bool TryGetMember(GetMemberBinder binder, out object result)
 
        {
 
            bool exito = false;
 
            result = null;
 
            if (_almacenDinamico.ContainsKey(binder.Name))
 
            {
 
                result = _almacenDinamico[binder.Name];
 
                exito = true;
 
            }
 
            else
 
            {
 
                result = "¡Propiedad no encontrada!";
 
                exito = false;
 
            }
 
            return exito;
 
        }
 
        public override bool TrySetMember(SetMemberBinder binder, object value)
 
        {
 
            _almacenDinamico[binder.Name] = value;
 
            return true;
 
        }
 
        public override bool TryInvokeMember(InvokeMemberBinder binder,
 
        object[] argumentos,
 
        out object resultado)
 
        {
 
            resultado = true;
 
  
 
            dynamic metodo = _almacenDinamico[binder.Name];
 
  
 
            metodo(argumentos[0]);
 
  
 
            return true;
 
        }
 
    }

Ver códigoExpandoObject

static void Main(string[] args)
 
       {
 
           dynamic objetoDinamico = new ExpandoObject();
 
           objetoDinamico.Nombre = "Carlos";
 
           objetoDinamico.Apellido = "García";
 
           objetoDinamico.Edad = 35;
 
 
 
           Action<dynamic> mostrar = (elemento) => Console.WriteLine("Mi nombre es " + elemento.Nombre + " " + elemento.Apellido
 
                                                              + ". Tengo " + elemento.Edad + " años.");
 
           objetoDinamico.Mostrar = mostrar;
 
 
 
           objetoDinamico.Mostrar(objetoDinamico);
 
 
 
           Console.Read();
 
       }

Ver códigoViewBag

public dynamic ViewBag
 
      {
 
          get
 
          {
 
              if (_datosVistaDinamicos == null)
 
              {
 
                  _datosVistaDinamicos = new DiccionarioDatosVistaDinamicos(() => ViewData);
 
              }
 
              return _datosVistaDinamicos;
 
          }
 
      }

Ver códigoLa definición de la clase DiccionarioDatosVistaDinamicos es la siguiente:

using System.Collections.Generic;
 
using System.Diagnostics;
 
using System.Dynamic;
 
  
 
namespace System.Web.Mvc
 
{
 
    internal sealed class DiccionarioDatosVistaDinamicos : DynamicObject
 
    {
 
        private readonly Func<ViewDataDictionary> _obtenerViewData;
 
  
 
        public DiccionarioDatosVistaDinamicos(Func<ViewDataDictionary> obtenerViewData)
 
        {
 
            _obtenerViewData = obtenerViewData;
 
        }
 
  
 
        private ViewDataDictionary ViewData
 
        {
 
            get
 
            {
 
                ViewDataDictionary datosVista = _obtenerViewData();
 
                Debug.Assert(datosVista != null);
 
                return datosVista;
 
            }
 
        }
 
  
 
        // Implementar este método mejora la experiencia de depuración al proporcionar al depurador la lista de todas
 
        // las propiedades actualmente definidas en el objeto
 
        public override IEnumerable<string> GetDynamicMemberNames()
 
        {
 
            return ViewData.Keys;
 
        }
 
  
 
        public override bool TryGetMember(GetMemberBinder binder, out object result)
 
        {
 
            result = ViewData[binder.Name];
 
            // Como ViewDataDictionary siempre devuelve un resultado incluso si la clave no existe, siempre devuelve true
 
            return true;
 
        }
 
  
 
        public override bool TrySetMember(SetMemberBinder binder, object value)
 
        {
 
            ViewData[binder.Name] = value;
 
            // Siempre se puede establecer una clave en el diccionario, por lo que devolvemos true
 
            return true;
 
        }
 
    }
 
}

Ver código


Etiquetas: c-sharp dynamic expandoobject dynamicobject aspnet-mvc

Publicado el 7-3 04:09