Scenari di metaprogrammazione leggera
Create helper guidati dagli attributi: etichette visualizzate, convalida dei campi obbligatori, un piccolo attivatore di costruttori e serializzazione simile al CSV, con chiare indicazioni di sicurezza.
Scenari di metaprogrammazione leggera è una lezione C# Academy gratuita su CoddyKit. Questa è la lezione 3 di 3. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento C# Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso C# Academy include 3 lezioni in totale.
Piano e ambito
Obiettivo: gestire piccoli comportamenti tramite attributi.
- Mappare le etichette
- Convalidare i campi obbligatori
- Un attivatore mini per la DI
- Serializzare in un formato simile al CSV
Etichette tramite attributi
Decori le proprietà con un DisplayName e lo legga tramite reflection per stampare etichette comprensibili.
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);
}
}
Convalida tramite attributi
Contrassegni le proprietà con Required; un piccolo validatore controlla i dati e segnala il primo campo mancante.
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);
}
}
Mini attivatore
Un piccolo attivatore associa un nome a ciascun parametro del costruttore. Fornisca valori predefiniti quando mancano.
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 tramite attributi
Ordini le colonne con CsvOrder ed esegua correttamente l'escape di virgole e virgolette.
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));
}
}
Suggerimenti e sicurezza
Suggerimenti:
- Preferisca typeof e i metadati memorizzati nella cache nei percorsi più utilizzati.
- Convalidi i membri prima di usare GetValue o Invoke.
- Mantenga gli helper ridotti e sottoposti a test unitari.
- Interrompa subito l'esecuzione con messaggi utili.
Indicazione per la reflection
Riepilogo
Riepilogo: gli attributi possono gestire piccoli mapper, validatori, attuatori e serializer. Mantenga la reflection al minimo e la usi in modo sicuro.
Domande Frequenti
La lezione «Scenari di metaprogrammazione leggera» è gratuita?
Sì — il testo completo di «Scenari di metaprogrammazione leggera» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso C# Academy, passa a CoddyKit PRO. Il corso C# Academy include 3 lezioni in totale.
Cosa imparerò in «Scenari di metaprogrammazione leggera»?
Create helper guidati dagli attributi: etichette visualizzate, convalida dei campi obbligatori, un piccolo attivatore di costruttori e serializzazione simile al CSV, con chiare indicazioni di sicurez… Eserciti C# Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare C# Academy?
Non è richiesta alcuna esperienza precedente. C# Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 3.
Quanto tempo richiede la lezione «Scenari di metaprogrammazione leggera»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione C# Academy?
Sì. Ogni lezione C# Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Type, MethodInfo, attivazione, attributi personalizzati
- Informazioni a livello di origine (attributi Caller)
- Scenari di metaprogrammazione leggera