0Pricing
C# Academy · Lección

Escenarios de metaprogramación ligera

Helpers basados en atributos: etiquetas de visualización, validación de campos obligatorios, un activador de constructores pequeño y serialización similar a CSV con consejos claros de seguridad.

Escenarios de metaprogramación ligera es una lección gratuita de C# Academy en CoddyKit. Esta es la lección 3 de 3. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C# Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C# Academy incluye 3 lecciones en total.

Planificación y alcance

Objetivo: Controle comportamientos pequeños mediante atributos.

  • Asigne etiquetas
  • Valide campos obligatorios
  • Activador pequeño de DI
  • Serialice en texto con formato similar a CSV

Etiquetas mediante atributos

Decore las propiedades con un DisplayName y use la reflexión para imprimir etiquetas claras.

using System;
using System.Reflection;

[AttributeUsage(AttributeTargets.Property)]
public sealed class DisplayNameAttribute : Attribute
{
  public string Text { get; private set; }
  public DisplayNameAttribute(string text) { Text = text; }
}

public sealed class User
{
  [DisplayName("User Id")]
  public int Id { get; set; }

  [DisplayName("Full Name")]
  public string Name { get; set; }
}

public class Program
{
  static void PrintWithLabels(object o)
  {
    if (o == null) throw new ArgumentNullException("o");
    Type t = o.GetType();
    foreach (PropertyInfo p in t.GetProperties())
    {
      object[] at = p.GetCustomAttributes(typeof(DisplayNameAttribute), false);
      string label = at.Length > 0 ? ((DisplayNameAttribute)at[0]).Text : p.Name;
      object val = p.GetValue(o, null);
      Console.WriteLine(label + ": " + (val == null ? "null" : val.ToString()));
    }
  }

  public static void Main(string[] args)
  {
    User u = new User { Id = 1, Name = "Ada" };
    PrintWithLabels(u);
  }
}

Validación mediante atributos

Marque las propiedades con Required; un validador pequeño comprueba los valores y notifica el primer campo que falta.

using System;
using System.Reflection;

[AttributeUsage(AttributeTargets.Property)]
public sealed class RequiredAttribute : Attribute { }

public sealed class Product
{
  [Required] public string Name { get; set; }
  public decimal Price { get; set; }
}

public class Program
{
  static bool Validate(object obj, out string error)
  {
    error = null;
    if (obj == null) { error = "object is null"; return false; }

    Type t = obj.GetType();
    foreach (PropertyInfo p in t.GetProperties())
    {
      object[] req = p.GetCustomAttributes(typeof(RequiredAttribute), false);
      if (req.Length > 0)
      {
        object v = p.GetValue(obj, null);
        if (v == null || (v is string && string.IsNullOrEmpty((string)v)))
        {
          error = "Required property missing: " + p.Name;
          return false;
        }
      }
    }
    return true;
  }

  public static void Main(string[] args)
  {
    Product ok = new Product { Name = "Mouse", Price = 10m };
    Product bad = new Product { Name = null, Price = 5m };

    string e;
    Console.WriteLine(Validate(ok, out e) ? "OK" : e);
    Console.WriteLine(Validate(bad, out e) ? "OK" : e);
  }
}

Activador pequeño

Un activador pequeño asigna un nombre a cada parámetro del constructor. Proporcione valores predeterminados cuando falten.

using System;
using System.Reflection;
using System.Collections.Generic;

public sealed class Repo { public string Name; public Repo(string name){ Name = name; } }

public sealed class Service
{
  public Repo R; public int Timeout;
  public Service(Repo repo, int timeout){ R = repo; Timeout = timeout; }
}

public class Program
{
  static object CreateWithArgs(Type t, IDictionary<string, object> args)
  {
    if (t == null) throw new ArgumentNullException("t");
    if (args == null) args = new Dictionary<string, object>();

    ConstructorInfo[] ctors = t.GetConstructors();
    if (ctors.Length == 0) throw new InvalidOperationException("No public constructor");

    ConstructorInfo ci = ctors[0];
    ParameterInfo[] ps = ci.GetParameters();
    object[] argv = new object[ps.Length];

    for (int i = 0; i < ps.Length; i++)
    {
      object val;
      if (args.TryGetValue(ps[i].Name, out val)) argv[i] = val;
      else if (ps[i].ParameterType.IsValueType) argv[i] = Activator.CreateInstance(ps[i].ParameterType);
      else argv[i] = null;
    }
    return ci.Invoke(argv);
  }

  public static void Main(string[] args)
  {
    IDictionary<string, object> map = new Dictionary<string, object>();
    map["repo"] = new Repo("Main");
    map["timeout"] = 30;

    Service s = (Service)CreateWithArgs(typeof(Service), map);
    Console.WriteLine(s.R.Name + " / " + s.Timeout);
  }
}

CSV mediante atributos

Ordene las columnas con CsvOrder y escape correctamente las comas y las comillas.

using System;
using System.Reflection;
using System.Text;
using System.Globalization;

[AttributeUsage(AttributeTargets.Property)]
public sealed class CsvOrderAttribute : Attribute
{
  public int Index { get; private set; }
  public CsvOrderAttribute(int index){ Index = index; }
}

public sealed class Row
{
  [CsvOrder(0)] public int Id { get; set; }
  [CsvOrder(1)] public string Name { get; set; }
  [CsvOrder(2)] public decimal Price { get; set; }
}

public class Program
{
  static int GetIndex(PropertyInfo p)
  {
    object[] at = p.GetCustomAttributes(typeof(CsvOrderAttribute), false);
    return at.Length > 0 ? ((CsvOrderAttribute)at[0]).Index : Int32.MaxValue;
  }

  static string ToCsv(object o)
  {
    if (o == null) throw new ArgumentNullException("o");
    Type t = o.GetType();
    PropertyInfo[] props = t.GetProperties();

    Array.Sort(props, delegate(PropertyInfo a, PropertyInfo b)
    {
      int ia = GetIndex(a), ib = GetIndex(b);
      return ia.CompareTo(ib);
    });

    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < props.Length; i++)
    {
      object v = props[i].GetValue(o, null);
      string cell = v == null ? "" : Convert.ToString(v, CultureInfo.InvariantCulture);

      if (i > 0) sb.Append(",");
      sb.Append(cell);
    }
    return sb.ToString();
  }

  public static void Main(string[] args)
  {
    Row r = new Row { Id = 7, Name = "Cable, HDMI", Price = 12.5m };
    Console.WriteLine(ToCsv(r));
  }
}

Consejos y seguridad

Consejos:

  • Prefiera typeof y metadatos almacenados en caché en rutas críticas.
  • Valide los miembros antes de usar GetValue o Invoke.
  • Mantenga los auxiliares pequeños y cubiertos por pruebas unitarias.
  • Falle rápidamente con mensajes útiles.

Directriz sobre reflexión

Comprobación rápida: ¿Cuál es una regla segura al usar reflexión para realizar metaprogramación ligera?

Resumen

Resumen: Los atributos pueden controlar pequeños mapeadores, validadores, activadores y serializadores. Mantenga la reflexión al mínimo y úsela de forma segura.

Preguntas frecuentes

¿La lección «Escenarios de metaprogramación ligera» es gratis?

Sí — el texto completo de «Escenarios de metaprogramación ligera» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C# Academy, actualiza a CoddyKit PRO. El curso de C# Academy incluye 3 lecciones en total.

¿Qué aprenderé en «Escenarios de metaprogramación ligera»?

Helpers basados en atributos: etiquetas de visualización, validación de campos obligatorios, un activador de constructores pequeño y serialización similar a CSV con consejos claros de seguridad. Practicas C# Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar C# Academy?

No se requiere experiencia previa. C# Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 3.

¿Cuánto tiempo toma la lección «Escenarios de metaprogramación ligera»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de C# Academy?

Sí. Cada lección de C# Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Type, MethodInfo, activación y atributos personalizados
  2. Información a nivel de código fuente (atributos Caller)
  3. Escenarios de metaprogramación ligera
← Volver a C# Academy